美文网首页
android listView

android listView

作者: MrMagicWang | 来源:发表于2016-07-22 16:29 被阅读79次

    ListView是一种以列表形式展示具体内容,并且能够根据数据的长度自适应显示的控件。一个listView通常有两个职责:一是将数据填充到布局,二是处理用户的选择点击操作等

    构建ListView的元素:
    - ListView中每一列的view。
    - 填入View的数据,如字符串、图片或组件。
    - 连接数据与ListView的适配器。

    适配器(Adapter)

    适配器是一个连接数据和AdapterView(ListView就是一个典型的AdapterView,其他的AdapterView还有Spinner, GridView, Gallery and StackView)的桥梁,通过它能有效地实现数据与AdapterView的分离设置,使AdapterView与数据的绑定更加简便,修改更加方便。下表为常用的adapter。

    Adapter 含义
    BaseAdapter 通用的基础适配器
    SimpleAdapter 用来绑定在xml中定义的控件对应的数据
    ArrayAdapter<T> 用来绑定一个数组,支持泛型操作
    SimpleCursorAdapter 用来绑定游标得到的数据
    listView使用BaseAdapter

    首先在布局文件中定义一个listView控件

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.kevinwang.test.TestListActivity">
        <ListView
            android:id="@+id/baseList"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@color/grey"
            android:dividerHeight="1dp"></ListView>
    </RelativeLayout>
    

    然后定义一个listView中每一行的布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
            <TextView
                android:id="@+id/list_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="20sp"/>
    </LinearLayout>
    

    使用BaseAdapter必须写一个类继承它,同时BaseAdapter是一个抽象类,继承它必须实现它的方法。当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()和getItemId()则在需要处理和取得Adapter中的数据时调用。

    public class TestListActivity extends AppCompatActivity {
        private ListView mListView;
        private String[] mStrArray;
        private MyBaseAdapter myBaseAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test_list);
    
            mListView = (ListView)findViewById(R.id.baseList);
    
            mStrArray = new String[30];
            for (int i = 0; i < 30; i++) {
                mStrArray[i] = String.valueOf(i);
            }
    
            myBaseAdapter = new MyBaseAdapter(this);
            mListView.setAdapter(myBaseAdapter);
    
            mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, 
                                        View view, int i, long l) {
                    TextView textView = (TextView)view.findViewById(R.id.list_text);
                    mStrArray[i] = String.valueOf(Integer.valueOf(mStrArray[i]) + 1);
                    myBaseAdapter.notifyDataSetChanged();
                }
            });
        }
    
        class MyBaseAdapter extends BaseAdapter {
            private Context mContext;
            private LayoutInflater mInflater; //得到一个LayoutInfalter对象用来导入布局
            private ViewHolder viewHolder;
    
            public MyBaseAdapter(Context context) {
                mContext = context;
                mInflater = (LayoutInflater) mContext.
                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            }
    
            @Override
            public int getCount() {
                //返回数据总数
                return mStrArray.length;
            }
    
            @Override
            public Object getItem(int i) {
                //返回某个位置的数据
                return mStrArray[i];
            }
    
            @Override
            public long getItemId(int i) {
                return i;
            }
    
            @Override
            public View getView(int i, View convertView, ViewGroup viewGroup) {
                if(convertView == null) {
                    convertView= mInflater.inflate(R.layout.test_list_item, null);
                    viewHolder = new ViewHolder();
                    viewHolder.textView = (TextView) convertView.findViewById(R.id.list_text);
                    convertView.setTag(viewHolder);  //绑定ViewHolder对象
                }
                else {
                    viewHolder = (ViewHolder)convertView.getTag(); //取出ViewHolder对象
                }
                Log.v("myListView", "getView " + i + " " + view);
                viewHolder.textView.setText(mStrArray[i]);
                return view;
    
            }
        }
    
        class ViewHolder {
            public TextView textView;
        }
    }
    

    为了响应列表项的点击事件,应该调用OnItemClickListener方法:

    listView.setOnItemClickListener(new OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent, View view,
        int position, long id) {
             ...............
      }
    }); 
    

    当数据改变时,adapter应该调用notifyDataSetChanged()方法来告知数据变化。


    那么getView如何使用呢?如果有10000行数据,就绘制10000次?这肯定会极大的消耗资源,导致ListView滑动非常的慢,那应该怎么做呢?

    代码中,在getView()方法中加入了一行log输出view的内容。滚动ListView,输出信息如如下图



      从图中可以看出,当启动Activity呈现第一屏ListView的时候,convertView为null并被分配了一系列的convertView的值。当往下滚屏时,发现第0行的容器用来容纳第14行,第1行的容器用来容纳第15行。也就是说convertView相当于一个缓存,当有条目变为不可见,它缓存了它的数据,后面再出来的条目只需要更新数据就可以了,这样大大节省了系统资料的开销。
      虽然重复利用了已经绘制的view,但是要得到其中的控件,需要在控件的容器中通过findViewById的方法来获得。如果这个容器非常复杂,这显然会增加系统资源的开销。在上面的例子中,引入了Tag的概念。或许不是最好的办法,但是它确实能使ListView变得更流畅。代码中,当convertView为空时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。当convertView不为空,重复利用已经创建的view的时候,使用getTag()方法获取绑定的ViewHolder对象,这样就避免了findViewById对控件的层层查询,而是快速定位到控件。

    当listView中的每个Item不同时怎么办?
    利用getItemViewType方法。

    listView的常用属性
    - listSelector
    - scrollingCache
    - cacheColorHint
    - fastScrollEnabled

    listView的常用方法
    - addHeaderView
    - addFooterView

    相关文章

      网友评论

          本文标题:android listView

          本文链接:https://www.haomeiwen.com/subject/hgcijttx.html