Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android——ListView控件

Android——ListView控件

編輯:關於Android編程

本篇介紹ListView控件,這是Android中比較重要也比較復雜的控件,這裡只談到使用ViewHolder機制優化即可。

一、ListView簡介

ListView是Android系統中顯示列表的控件,每個ListView都可以包含很多個列表項。
這裡寫圖片描述

二、ListView的使用

概念不多說,直接來介紹使用方法。
ListView中比較復雜的是數據適配器,其作用是把復雜的數據(數組、鏈表、數據庫、集合等)填充在指定視圖界面,是連接數據源和視圖界面的橋梁。常見的Android原生的適配器有ArrayAdapter和SimpleAdapter。
使用步驟:新建適配器->添加數據源到適配器->視圖加載適配器

1. ArrayAdapter(數組適配器)

適用:用於綁定格式單一的數據;
數據源:可以使集合或數組。

public class MainActivity extends Activity {
    private ListView listView;
// 1. 新建一個數據適配器
    private ArrayAdapter arr_aAdapter; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView)findViewById(R.id.listView1);
        //  創建適配器對象時將數據加載到適配器裡
   /**new ArrayAdapter(context, textViewResourceId)
         * context--  上下文,一般為this
         * textViewResourceId-- 當前ListView加載的每一個列表項所對應的布局文件【這裡采用系統默認的一個布局android.R.layout.simple_list_item_1】
      */
      //  2. 添加數據源到適配器
        String[] arr_data = {"fanff", "fan", "tencent", "QQ"};// 創建的數據源
        arr_aAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, arr_data);
        // 3. 視圖(ListView)加載適配器
        listView.setAdapter(arr_adAdapter);
    }    
}

2. SimpleAdapter(簡單適配器)

適用:綁定格式復雜的數組;
數據源:只能是特定泛型的集合。

public class MainActivity extends Activity {
    private ListView listView;
    private SimpleAdapter sim_aAdapter; // 1. 新建一個數據適配器

    private List>dataList; // 數據源

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        listView = (ListView)findViewById(R.id.listView1); 

        /** SimpleAdapter(context, data, resource, from, to)
         *  context: 上下文
         *  data: 數據源(List> data),一個Map所組成的List集合
         *        每個Map都會對應ListView列表中的一行,Map是由鍵【必須包含所有在from中所指定的鍵】值對組成
         *  resource:列表中的布局文件的ID,此處的布局是自定義的
         *  from:Map中的鍵名
         *  to:綁定數據視圖中的ID,與from成對應關系
         */  
        // 2. 適配器加載數據源
        dataList = new ArrayList>();
        sim_aAdapter = new SimpleAdapter(this, getData(), R.layout.item, new String[]{"pic0", "text0"}, new int[]{R.id.pic, R.id.text}); 
        // 3. 視圖(ListView)加載適配器
        listView.setAdapter(sim_aAdapter);        
    }

   private List> getData(){
       for (int i = 0; i < 20; i++){
           Mapmap = new HashMap();
           map.put("pic0", R.drawable.ic_launcher);
           map.put("text0", "fanff"+i);
           dataList.add(map);
       }
       return dataList;
   }   
}

一般來講,簡單適配器的數據源是一個集合,所以一般寫一個方法來處理(例如getData())。

其中自定義的item.xml布局




    

    

3.繼承BaseAdapter的自定義的適配器

這個玩法比較多,這裡先不介紹,直接見下面的。

4. 監聽器

(1). 監聽器是程序和用戶(或系統)交互的橋梁,這裡不多講了,畢竟用的多。ListView中的兩個常用監聽器:OnItemClickListener和OnScrollListener。
(2). OnItemClickListener可以處理視圖中單個條目的點擊事件;OnScrollListener監測滾動的變化,可以用於視圖在滾動中加載數據。

public class MainActivity extends Activity implements OnItemClickListener,
        OnScrollListener {
    private ListView listView;
    private ArrayAdapter arr_aAdapter;
    private SimpleAdapter sim_aAdapter;

    private List> dataList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        listView = (ListView) findViewById(R.id.listView1);

        /**
         * 1. 新建一個數據適配器 context: 上下文 data: 數據源(List>
         * data),一個Map所組成的List集合
         * 每個Map都會對應ListView列表中的一行,Map是由鍵【必須包含所有在from中所指定的鍵】值對組成 from:Map中的鍵名
         * resource:列表中的布局文件的ID to:綁定數據視圖中的ID,與from成對應關系
         */
        // 2. 適配器加載數據源
        dataList = new ArrayList>();
        sim_aAdapter = new SimpleAdapter(this, getData(), R.layout.item,
                new String[] { "pic0", "text0" }, new int[] { R.id.pic,
                        R.id.text });
        // 3. 視圖(ListView)加載適配器
        listView.setAdapter(sim_aAdapter);

        // 監聽器
        listView.setOnItemClickListener(this);// 單擊單個條目
        listView.setOnScrollListener(this);// 視圖在滾動中加載數據
    }

    private List> getData() {
        for (int i = 0; i < 20; i++) {
            Map map = new HashMap();
            map.put("pic0", R.drawable.ic_launcher);
            map.put("text0", "fanff" + i);
            dataList.add(map);
        }
        return dataList;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        switch (scrollState) {
        case SCROLL_STATE_FLING:
            Log.i("ScrollState", "用戶在手指離開屏幕之前,由於用力滑了一下,視圖仍依靠慣性在繼續滑行");
            Map map = new HashMap();
            map.put("pic0", R.drawable.ic_launcher);
            map.put("text0", "fresh");
            dataList.add(map);
            sim_aAdapter.notifyDataSetChanged();// 通知UI進程刷新界面
            break;
        case SCROLL_STATE_IDLE:
            Log.i("ScrollState", "視圖已經停止滑動");
            break;
        case SCROLL_STATE_TOUCH_SCROLL:
            Log.i("ScrollState", "手指乜有離開屏幕,視圖正在滑動");
            break;
        default:
            break;
        }
    }

    @Override
    public void onItemClick(AdapterView parent, View view, int position,
            long id) {
        // TODO Auto-generated method stub
        String text = listView.getItemAtPosition(position) + "";// 指定位置的內容
        Toast.makeText(this, "positon=" + position + "text" + text,
                Toast.LENGTH_LONG).show();
    }
}

三、ListView中的BaseAdapter

這裡著重來介紹一下BaseAdapter,各種方式的比較見代碼注釋。
源碼下載:https://github.com/herdyouth/ListView
MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        List itemBeanList = new ArrayList<>();
        for (int i = 0; i < 20; i++){
            itemBeanList.add(new ItemBean(R.mipmap.ic_launcher,
                    "標題" + i, "內容" + i));
        }

        // 數據源與適配器的綁定
        ListView listView = (ListView) findViewById(R.id.lview);
        listView.setAdapter(new MyBaseAdapter(this, itemBeanList));
    }
}

BaseAdapter各種方式的對比,一步步優化的原因如代碼注釋

/**
 * 創建數據適配器
 * Created by herd_youth on 2016/4/15.
 */
public class MyBaseAdapter extends BaseAdapter{

    private List mList;
    private LayoutInflater mInflater;

    // 通過構造器關聯數據源與數據適配器
    public MyBaseAdapter(Context context, List list){
        mList = list;
        // 使用當前要使用的界面對象context去初始化布局裝載器對象mInflater
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

    // 返回指定索引對應的數據項
    @Override
    public long getItemId(int position) {
        return position;
    }


   /* *//**
     * 返回每一項對應的內容
     * 缺點:沒有利用到ListView的緩存機制
     *      每次都會創建新的View,不管當前這個Item是否在屏幕上被調用過(即是否被緩存過)
     * @param position
     * @param convertView
     * @param parent
     * @return
     *//*
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 將布局文件轉為View對象
        View view = mInflater.inflate(R.layout.item, null);
        ImageView imageView = (ImageView) view.findViewById(R.id.iv_img);
        TextView title = (TextView) view.findViewById(R.id.tv_title);
        TextView content = (TextView) view.findViewById(R.id.tv_content);
        ItemBean bean = mList.get(position);
        imageView.setImageResource(bean.getItemImageResid());
        title.setText(bean.getItemContent());
        content.setText(bean.getItemContent());

        return view;
    }*/

    /**
     * 改善處:使用系統的convertView來較好的利用ListView的緩存機制,避免重復大量的創建convertView
     * 缺點:findViewById依然會浪費大量的時間去調用視圖樹
     * @param position
     * @param convertView
     * @param parent
     * @return
     *//*
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null){// View未被實例化,即緩沖池中無緩存才創建View
            convertView = mInflater.inflate(R.layout.item, null);
        }else{
            ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_img);
            TextView title = (TextView) convertView.findViewById(R.id.tv_title);
            TextView content = (TextView) convertView.findViewById(R.id.tv_content);
            ItemBean bean = mList.get(position);
            imageView.setImageResource(bean.getItemImageResid());
            title.setText(bean.getItemContent());
            content.setText(bean.getItemContent());
        }
        return convertView;
    }*/

    /**
     * 既利用了ListView的緩存,
     * 更通過ViewHolder類來顯示數據的視圖的緩存,避免了多次通過findViewById尋找控件
     * @param position
     * @param convertView
     * @param parent
     * @return
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null){// View未被實例化,即緩沖池中無緩存才創建View
            // 將控件id保存在viewHolder中
            viewHolder = new ViewHolder();
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_img);
            viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title);
            viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content);
            // 通過setTag將ViewHolder與convertView綁定
            convertView.setTag(viewHolder);
        } else{
            // 通過ViewHolder對象找到對應控件
            viewHolder = (ViewHolder) convertView.getTag();
            ItemBean bean = mList.get(position);
            viewHolder.imageView.setImageResource(bean.getItemImageResid());
            viewHolder.title.setText(bean.getItemContent());
            viewHolder.content.setText(bean.getItemContent());
        }
        return convertView;
    }

    // 避免重復的findViewById的操作
    class ViewHolder{
        public ImageView imageView;
        public TextView title;
        public TextView content;
    }
}
/**
 * 創建設置每個Item的類
 * Created by herd_youth on 2016/4/15.
 */
public class ItemBean {
    private int ItemImageResid;
    private String ItemTitle;
    private String ItemContent;

    public ItemBean(int itemImageResid, String itemTitle, String itemContent) {
        ItemImageResid = itemImageResid;
        ItemTitle = itemTitle;
        ItemContent = itemContent;
    }

    public int getItemImageResid() {
        return ItemImageResid;
    }

    public void setItemImageResid(int itemImageResid) {
        ItemImageResid = itemImageResid;
    }

    public String getItemTitle() {
        return ItemTitle;
    }

    public void setItemTitle(String itemTitle) {
        ItemTitle = itemTitle;
    }

    public String getItemContent() {
        return ItemContent;
    }

    public void setItemContent(String itemContent) {
        ItemContent = itemContent;
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved