一. 前言 1. 什么是 ListView ? 它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示。
1 2 3 4 5 6 java.lang.Object ↳android.view.View ↳android.view.ViewGroup ↳android.widget.AdapterView<T extends android.widget.Adapter> ↳android.widget.AbsListView ↳android.widget.ListView
二. ListView的属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 android:cacheColorHint="#00000000":去除listview的拖动背景色 android:listSelector="#00000000":设置item被选中之后的颜色 android:divider:分割线的颜色 android:dividerHeight:分隔线的高度 android:scrollbars="none" 取消右侧滑动条 android:entries:对将填充ListView的数组资源的引用。 android:footerDividersEnabled:当设置为false时,ListView不会在每个页脚视图之前绘制分隔符。 android:headerDividersEnabled:当设置为false时,ListView不会在每个标题视图之后绘制分隔符。 addHeaderView()方法:主要是向listView的头部添加布局。 addFooterView()方法:主要是向listView的底部添加布局。
三. ListView的Adapter 1. ArrayAdapter 用来绑定一个数组,支持泛型操作,最简单的一个Adapter
,只能展现一行文字。
2. SimpleAdapter 用来绑定在xml
中定义的控件对应的数据,同样具有良好扩展性的一个Adapter
,可以自定义多种效果。
3. SimpleCursorAdapter 用来绑定游标得到的数据。可以认为是 SimpleAdapter 和数据库的简单集合。
4. BaseAdapter 通用的基础适配器,抽象类。实际开发中我们会继承这个类并且重写BaseAdapter
的四个方法,可以完成自己定义的Adapter
,可以将任何复杂组合的数据和资源,以任何你想要的显示效果展示给大家用得最多的一个Adapter
。
使用参考:Android ListView入门知识–各种Adapter配合使用
四. BaseAdapter的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private class MyAdapter extends BaseAdapter { @Override public int getCount () { } @Override public Object getItem (int position) { } @Override public long getItemId (int position) { } @Override public View getView (int position, View convertView, ViewGroup parent) { } }
1. MVC的设计思想 M-Model:模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class FriendBean { public int icon_id; public String name; public FriendBean (int icon_id, String name) { this .icon_id = icon_id; this .name = name; } }
V-View:视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:orientation ="horizontal" android:layout_width ="match_parent" android:layout_height ="wrap_content" > <swu.xl.listview.XLImageView android:tag="@string/icon" android:layout_width="100dp" android:layout_height="100dp" android:scaleType="fitXY" /> <TextView android:tag="@string/name" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="24sp" android:textStyle="bold" android:textColor="#000" /> </LinearLayout >
C-Controller:控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class FriendItem { private FriendBean bean; private int layout; private View item_view; public FriendItem (FriendBean bean, Context context) { this .bean = bean; this .layout = R.layout.friend_layout; initView(context); } private void initView (Context context) { View inflate = LayoutInflater.from(context).inflate(layout, null ); ImageView icon_view = inflate.findViewWithTag(context.getResources().getString(R.string.icon)); TextView name_view = inflate.findViewWithTag(context.getResources().getString(R.string.name)); icon_view.setImageResource(bean.icon_id); name_view.setText(bean.name); item_view = inflate; } public View getItem_view () { return item_view; } }
2. 数据管理 数据的来源有很多,我们需要用一个单例类来管理我们的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class DataManager { private List<FriendBean> beans; private static DataManager instance = null ; private DataManager () { loadData(); } public static synchronized DataManager getDataManager () { if (instance == null ){ instance = new DataManager(); } return instance; } private void loadData () { beans = DataUtil.loadData(); } public List<FriendBean> getBeans () { return beans; } }
3. 加载数据的方式 加载数据的方式有很多,为了便于扩展,才有了这个工具类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class DataUtil { public static List<FriendBean> loadData () { List<FriendBean> friendBeans = new ArrayList<>(); for (int i = 0 ; i < 30 ; i++) { FriendBean friendBean = new FriendBean(R.drawable.ic_launcher_background, "第" + i + "个" ); friendBeans.add(friendBean); } return friendBeans; } public static List<FriendBean> loadDateByFile () { return null ; } public static List<FriendBean> loadDateBySQL () { return null ; } public static List<FriendBean> loadDateByServer () { return null ; } }
4. ListView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public class XLListView extends ListView { public XLListView (Context context) { super (context); initData(); } public XLListView (Context context, AttributeSet attrs) { super (context, attrs); initData(); } private void initData () { setAdapter(new MyAdapter()); } private class MyAdapter extends BaseAdapter { @Override public int getCount () { return DataManager.getDataManager().getBeans().size(); } @Override public Object getItem (int position) { return DataManager.getDataManager().getBeans().get(position); } @Override public long getItemId (int position) { return position; } @Override public View getView (int position, View convertView, ViewGroup parent) { FriendBean bean = DataManager.getDataManager().getBeans().get(position); FriendItem item = new FriendItem(bean, getContext()); return item.getItem_view(); } } }
5. 简单的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:tools ="http://schemas.android.com/tools" android:layout_width ="match_parent" android:layout_height ="match_parent" tools:context =".MainActivity" > <swu.xl.listview.XLListView android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout >
6. Github地址 ListView
五. ListView的优化 1. 使用convertView 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class FriendItem { private FriendBean bean; private int layout; private View item_view; public FriendItem (FriendBean bean, Context context, View convertView) { this .bean = bean; this .layout = R.layout.friend_layout; initView(context,convertView); } private void initView (Context context,View convertView) { if (convertView == null ){ convertView = LayoutInflater.from(context).inflate(layout, null ); } ImageView icon_view = convertView.findViewWithTag(context.getResources().getString(R.string.icon)); TextView name_view = convertView.findViewWithTag(context.getResources().getString(R.string.name)); icon_view.setImageResource(bean.icon_id); name_view.setText(bean.name); item_view = convertView; } public View getItem_view () { return item_view; } }
1 2 3 4 5 6 7 8 9 @Override public View getView (int position, View convertView, ViewGroup parent) { FriendBean bean = DataManager.getDataManager().getBeans().get(position); FriendItem item = new FriendItem(bean, getContext(), convertView); return item.getItem_view(); }
2. ViewHolder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class FriendItem { private FriendBean bean; private int layout; private View item_view; public FriendItem (FriendBean bean, Context context, View convertView) { this .bean = bean; this .layout = R.layout.friend_layout; initView(context,convertView); } private void initView (Context context,View convertView) { ViewHolder viewHolder; if (convertView == null ){ convertView = LayoutInflater.from(context).inflate(layout, null ); viewHolder = new ViewHolder(); viewHolder.icon_view = convertView.findViewWithTag(context.getResources().getString(R.string.icon)); viewHolder.name_view = convertView.findViewWithTag(context.getResources().getString(R.string.name)); convertView.setTag(viewHolder); }else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.icon_view.setImageResource(bean.icon_id); viewHolder.name_view.setText(bean.name); item_view = convertView; } private class ViewHolder { public ImageView icon_view; public TextView name_view; } public View getItem_view () { return item_view; } }
优化的方式都是尽量避免多次inflate和findView这些耗时操作。
六. 监听点击的item 1. 监听item被点击 1 2 3 4 5 6 7 8 XLListView listView = findViewById(R.id.list_view); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick (AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this , "位置" +position+"被点击了" , Toast.LENGTH_SHORT).show(); } });
2. 监听item被长按了 1 2 3 4 5 6 7 8 9 XLListView listView = findViewById(R.id.list_view); listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick (AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this , "位置" +position+"被长按了" , Toast.LENGTH_SHORT).show(); return true ; } });
七. 刷新ListView 1. 重写getAdapter获取自己写的Adapter类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 public class XLListView extends ListView { private MyAdapter adapter; public XLListView (Context context) { super (context); initData(); } public XLListView (Context context, AttributeSet attrs) { super (context, attrs); initData(); } private void initData () { adapter = new MyAdapter(); setAdapter(adapter); } public class MyAdapter extends BaseAdapter { @Override public int getCount () { return DataManager.getDataManager().getBeans().size(); } @Override public Object getItem (int position) { return DataManager.getDataManager().getBeans().get(position); } @Override public long getItemId (int position) { return position; } @Override public View getView (int position, View convertView, ViewGroup parent) { FriendBean bean = DataManager.getDataManager().getBeans().get(position); FriendItem item = new FriendItem(bean, getContext(), convertView); return item.getItem_view(); } } @Override public MyAdapter getAdapter () { return adapter; } }
2. 调用 Adapter类 的notifyDataSetChanged方法刷新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); final XLListView listView = findViewById(R.id.list_view); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick (AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this , "位置" +position+"被点击了" , Toast.LENGTH_SHORT).show(); XLListView.MyAdapter adapter = listView.getAdapter(); if (position == 0 ){ List<FriendBean> beans = DataManager.getDataManager().getBeans(); if (beans.size() == 1 ){ beans.clear(); beans.addAll(DataUtil.loadData()); adapter.notifyDataSetChanged(); }else { beans.clear(); beans.add(new FriendBean(R.drawable.ic_launcher_foreground,"新的item" )); adapter.notifyDataSetChanged(); } } } }); listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick (AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this , "位置" +position+"被长按了" , Toast.LENGTH_SHORT).show(); return true ; } }); } }
3. 运行结果
4. 参考: ListView的动态刷新问题——用notifyDataSetChanged没作用
Android开发中更新UI时runOnUIthread(Runnable)与Handler.post(Runnable)的区别及如何选择
Adapter的notifyDataSetInvalidated()和notifyDataSetChanged()的区别
七. 小问题 1. 设置每一个item的高度 如何设置listview每个item高度
2. 取消item被点击的水波纹效果 ListView布局中加上android:listSelector=”@android:color/transparent” 。
八. 进阶 1. 风格不同的item 参考:Android之ListView的getItemViewType和getViewTypeCount
参考文章 这个控件你必须会用!—ListView+GirdView
ListView中BaseAdapter的详细使用以及优化