虽然已经有了RecyclerView,但是ListView还是有他的好处的,比较简单
如果学RecyclerView之前先学ListView会有很大的其实的,比如说ViewHolder
首先我们应该在XML的layout处写出ListView布局
<!--
android:divider="#000" 给间隔线加颜色
android:dividerHeight="10sp" 给间隔线设置高度
android:scrollbars="none" 设置右边的滚动条
none为没有
android:fadeScrollbars="false" 设置右边的滚动条(自动显示的)
-->
<!--要对ListView里面的item项做Select选择器(按下去变色)
要对整体进行设置,不能对行布局进行设置(要改变系统)
listView原来有一个系统定义好的切换的一套算法
所以把他替换要改整个listView(整体)
android:listSelector="@drawable/item_selector"用这个属性
由整个ListView做全局的处理
-->
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:listSelector="@drawable/item_selector"
/>
现在ListView有三种适配器
1、数组适配器ArrayAdapter,只能显示简单是String
实现他很简单,主要是分四部
//1、获得ListView对象
ListView listView = (ListView) findViewById(R.id.listView);
//2、准备数据源
String[] data = {" * 1、获得ListView对象"
, " * 2、准备数据源"
, " * 3、准备适配器Adapter"
, " * 4、将适配器关联到ListView"};
//3、准备适配器
ArrayAdapter<String> adapter =
new ArrayAdapter<>(this
, android.R.layout.simple_list_item_1
, data);
//4、适配器关联ListView
listView.setAdapter(adapter);
第二种:简单适配器SimpleAdapter,其实也是比较简单的
实现他也是分四步:
private List<Map<String,Object>> mMapList;
//1、声明出ListView
mListView = (ListView) findViewById(R.id.listView);
//2、准备数据源
mMapList = new ArrayList<>();
Map<String , Object> map = new HashMap<>();
map.put("logo" , R.drawable.music);
map.put("title" , "千千静音");
map.put("version" , "版本:2.4.1");
map.put("size" , "大小:32.1M");
mMapList.add(map);
map = new HashMap<>();
map.put("logo" , R.drawable.calendar);
map.put("title" , "计算器");
map.put("version" , "版本:1.4.1");
map.put("size" , "大小:12.1M");
mMapList.add(map);
map = new HashMap<>();
//把这个R.drawable.Maps转换成图片是SimpleAdapter自己的事情,内部有实现
map.put("logo" , R.drawable.maps);
map.put("title" , "地图");
map.put("version" , "版本:3.5.1");
map.put("size" , "大小:35.6M");
mMapList.add(map);
map = new HashMap<>();
map.put("logo" , R.drawable.camera);
map.put("title" , "照相机");
map.put("version" , "版本:1.0.0");
map.put("size" , "大小:22.12M");
mMapList.add(map);
//3、设置适配器
SimpleAdapter simpleAdapter =
new SimpleAdapter(this //上下文
,mMapList //数据源
,R.layout.item_simple_adapter //行布局
/**
* Key与id要保证一一对应 必须对应相应的
* 意思为:用logo key对应的value填入R.id.logo所对应的布局中
*/
,new String[]{"logo", "title" , "version" , "size"}
//键值对的key 要与键值对的key完全一样
,new int[]{R.id.logo , R.id.title , R.id.version , R.id.size}); //行布局中的id
//4、关联Adapter
mListView.setAdapter(simpleAdapter);
最后一种的BaseAdapter(个人觉得是最重要的),一般用来重写的
里面已经包含了优化ListView了,要仔细阅读哦
- 首先从写BaseAdapter,继承BaseAdapter
/**
*ListView的优化(控制次数)---》先一级后二级
* 每次调用getView()方法都要执行两个耗时操作
* 1、inflate方法(获得布局对象)----》》一级优化
* 通过用convertView解决
* 2、findViewById方法(获得控件对象)----》》二级优化
* 通过自定义的ViewHolder解决
*
*
* 看到这个优化很容易就想起了RecyclerView的ViewHolder,现在终于知道了Viewholder的来源了吧
*/
public class MyAdapter extends BaseAdapter{
private List<Map<String , Object>> list; //传入的数据
private LayoutInflater inflater; //反射器
public MyAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
public void setList(List<Map<String , Object>> list){
this.list = list;
}
/**
* 返回数据源的数量 决定了界面一共多少行
* @return
*/
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
/**
* 自定义适配器的核心方法
* 通过LayoutInflater反射出行布局对象,并且填充上数据内容
* 返回一个视图 填充好布局 等着调用 每显示一行调用一次
*
* ConvertView的工作原理
* 无论总量为多少,Android只渲染当前屏的item项
* 被渲染过的Item项,它的视图对象会被保存到Recycler中
* 新滑入屏幕的item项将从Recycler中直接获取缓存的视图,而不是再通过
* inflate方法反射获取
* 结论:
* 无论总量是多少,Recycler中只需要缓存N+1个视图对象,即可保证整个ListView
* 的显示(N为一屏幕可显示的Item数)
* 无论总量为多少,inflate方法最多调用N+1次
*
* @param i
* @param convertView 代表从缓冲区里面拿到的缓冲视图对象 一开始缓冲区里面什么都没有为null 后来有了就直接取出就可
* @param viewGroup
* @return
*/
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
ViewHolder holder = null;
/**
* 反射器:把XML的布局反射为一个view对象
*/
if(convertView == null) {
convertView = inflater.inflate(R.layout.item_simple_adapter, null);
holder = new ViewHolder();
holder.logo= (ImageView)convertView.findViewById(R.id.logo);
holder.title =(TextView)convertView.findViewById(R.id.title);
holder.version=(TextView)convertView.findViewById(R.id.version);
holder.size = (TextView)convertView.findViewById(R.id.size);
//viewHolder与convertView关联起来
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
Map<String , Object> map = list.get(i);
holder.logo.setImageResource((Integer) map.get("logo"));
holder.title.setText( (String)map.get("title"));
holder.version.setText((String) map.get("version"));
holder.size.setText((String) map.get("size"));
return convertView;
}
private class ViewHolder {
ImageView logo;
TextView title;
TextView version;
TextView size;
}
}
- 然后使用我们从写的BaseAdapter
private List<Map<String, Object>> mMapList;
//1、声明出ListView
mListView = (ListView) findViewById(R.id.listView);
//2、准备数据源
mMapList = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
map.put("logo", R.drawable.music);
map.put("title", "千千静音");
map.put("version", "版本:2.4.1");
map.put("size", "大小:32.1M");
mMapList.add(map);
map = new HashMap<>();
map.put("logo", R.drawable.calendar);
map.put("title", "计算器");
map.put("version", "版本:1.4.1");
map.put("size", "大小:12.1M");
mMapList.add(map);
map = new HashMap<>();
//把这个R.drawable.Maps转换成图片是SimpleAdapter自己的事情,内部有实现
map.put("logo", R.drawable.maps);
map.put("title", "地图");
map.put("version", "版本:3.5.1");
map.put("size", "大小:35.6M");
mMapList.add(map);
map = new HashMap<>();
map.put("logo", R.drawable.camera);
map.put("title", "照相机");
map.put("version", "版本:1.0.0");
map.put("size", "大小:22.12M");
mMapList.add(map);
//3、设置适配器
MyAdapter adapter = new MyAdapter(this);
adapter.setList(mMapList);
//4、关联Adapter
mListView.setAdapter(adapter);
//5、对每一项做监听事件 不是对listView而是对里面的每一项
//短瞬间的点击
mListView.setOnItemClickListener(this);
//长按
mListView.setOnItemLongClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(this , "点击item"+ i , Toast.LENGTH_SHORT).show();
}
/**
* 返回值
* true 表示消化掉事件,事件不会继续传递
* false 表示不消化事件,事件将继续传递下去
* 结论:如果希望长按事件后,不再触发点击事件,则应将返回值设置为true
* @param adapterView
* @param view
* @param i
* @param l
* @return
*/
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(this , "长按item"+ i , Toast.LENGTH_SHORT).show();
return true;
}