Adapter基礎

這里介紹的Adapter的基本應用主要來自于《第一行代碼》的第三章第5節內容,而在此處主要介紹的是ArrayAdapter,其中ArrayAdapterBaseAdapter的子類

Adapter基本理解

public class MainActivity extends Activity {

    String[] s = {"第1個列表項","第1個列表項","第1個列表項"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView listView = (ListView) findViewById(R.id.listView);
        ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_expandable_list_item_1,s);
        listView.setAdapter(adapter);
    }

}

其中ArrayAdapter的聲明是

new ArrayAdapter(MainActivity.this,android.R.layout.simple_expandable_list_item_1,s)

這里有三個參數,分別表示:

  1. 當前上下文(context
  2. 子項布局的id(textViewResourceId):這里的布局是使用了系統自帶的
  3. 要適配的數據(objects

可以將其理解為視圖 + 布局 —— 橋梁 —— 數據,其中Adapter就是橋梁

如同:
書籍要整理回到書架上,整個大書架就是視圖,書架上的格子就是布局,許許多多的書就是數據,而我就是它們之間的橋梁,也就是Adapter

Adapter進階

核心代碼如下:

public class FruitArrayAdapter extends ArrayAdapter {

    private int resourceId;

    public FruitArrayAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = (Fruit) getItem(position);
        View view = LayoutInflater.from(getContext()).inflate(resourceId,null);
        ImageView fruitIamge = (ImageView) view.findViewById(R.id.fruitImage);
        TextView fruitText = (TextView) view.findViewById(R.id.fruitText);
        fruitIamge.setImageResource(fruit.getImageId());
        fruitText.setText(fruit.getName());
        return view;
    }
}

其中ArrayAdapter的聲明是

fruitArrayAdapter = new FruitArrayAdapter(MainActivity.this,R.layout.fruit_listview,fruitList);

可以看到,因為要顯示的內容復雜了,ListView里面還需要給每一個item定義顯示的格式,這個顯示的格式就是布局R.layout.fruit_item
,它包含了兩個組件,一個是<ImageView/>用來顯示一張圖片,一個是<TextView/>用來顯示文字

然而為了能夠將R.layout.fruit_item顯示出來,就必須要重寫ArrayAdapter中的getView()方法,下面詳細解釋為什么

為何要重寫getView()方法

根據官方的描述:

A concrete BaseAdapter that is backed by an array of arbitrary objects. By default this class expects that the provided resource id references a single TextView. If you want to use a more complex layout, use the constructors that also takes a field id. That field id should reference a TextView in the larger layout resource.
However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.
To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override getView(int, View, ViewGroup) to return the type of view you want.

也就是說,默認情況下ArrayAdapter只能讓你傳一個TextView控件,例如R.layout.simple_expandable_list_item_1,如果想要顯示<TextView/>以外的控件,像是<ImageView/>,就必須重寫getView()方法

如何定義新的ArrayAdapter

public class FruitAdapter extends ArrayAdapter<Fruit>{
    private int resourceId;
    
    public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    @SuppressLint("ViewHolder")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = getItem(position);//獲取當前項的Fruit實例
        View view;
        ViewHolder viewHolder;
        if(convertView == null){//convertView用于將之前加載好的布局進行緩存
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
            viewHolder.fruitName = (TextView)view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);//將viewHolder存儲在View中
        }
        else{
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }
    
    class ViewHolder{
        ImageView fruitImage;
        TextView fruitName;
    }
}

在實際的工作中,為了更為方便的理解和管理代碼,最好的是直接定義一個新的ArrayAdapter,比如FruitAdapter,這樣更容易理解,然后在FruitAdapter中重寫getView()方法

getView(int position, View convertView, ViewGroup parent)方法的中的參數:

  1. position:表示我們現在正在繪制ListView中第幾個item
  2. converview:view控件的緩存裝置

所以為了給當前正在繪制的item設置要顯示的數據,首先需要拿到當前item條目對應在數據庫中的數據

//因為這個程序中每個item的數據為Fruit
Fruit fruit = getItem(position);

為何在Adapter的函數中可以拿到數據庫中的數據,這是因為在實現Adapter時,MainActivity首先會初始化Adapter

FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);

初始化時就會傳入數據庫fruitList,如此就能夠通過getItem(position)方法知道當前item正在使用數據庫fruitList中的哪一條

當然僅僅知道要用數據庫中的哪一條數據是不夠的,同時還要將這條數據按照一定的格式填入到item視圖中,這個格式就是R.layout.fruit_item

所以在程序中還定義FruitAdapter的構造方法public FruitArrayAdapter(Context context, int textViewResourceId, List<Fruit> objects) {……,就是為了獲得布局R.layout.fruit_item的id(類型為int),從而利用LayoutInflater為當前item視圖加載我們自定義布局

view = LayoutInflater.from(getContext()).inflate(resourceId, null);

這之后再把數據按照布局填入

最后返回填好數據的視圖

參考資料

【Android】我討厭“Adapter”這個單詞!!!(一)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容