最近学到ListView和RecyclerView,感觉有点难理解,于是自己找到了篇文章,感觉写的挺详细的(文章链接在文末),然后自己再整理敲了跑了一遍,总结了一下,方便自己以后回头温习。
一个ListView的创建需要三个元素
- ListView每一列的View
- 填入View的每一项数据(图片,文字等)
- 连接数据与ListView的适配器
什么是适配器?
适配器是一个连接数据和AdapterView(ListView、RecyclerView等)的桥梁,通过它能有效地实现数据与AdaperView的分离设置,使得AdapterView与数据的绑定更加简便,修改更方便。
1. ListView使用ArrayAdapter
默认情况下,ArrayAdapter绑定每一个对象的toString值到layout中预先定义的TextView控件上。
例子
在activity_main_xml布局文件中加入一个ListView控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
在MainActivity中进行初始化
public class MainActivity extends AppCompatActivity {
//用一个数组来listView的每一项数据
private String[] s = {"aa", "bb", "cc", "dd", "ee", "ff", "gg", "hh", "ii"};
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过id找到listView对象
listView = findViewById(R.id.listView);
//给listView设置ArrayAdapter,绑定数据
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, s));
}
}
步骤:
-
建立一个String类型的数据作为每一项Item的显示数据
-
初始化listView对象
-
给listView设置适配器,并通过ArrayAdapter的构造器绑定数据
例子中使用的ArrayAdapter构造器有三个参数,第一个参数是上下文,可以传一个当前对象this,第二个参数是布局资源(必须要有TextView控件),例子里用的是系统自带的android.R.layout.simple_list_item_1(还有几种常用的:android.R.layout.simple_list_item_checked、android.R.layout.simple_list_item_multiple_choice、android.R.layout.simple_list_item_single_choice),第三个参数是ListView的具体内容,例子就用的一个字符串数组。
android.R.layout.simple_list_item_checked:实现带选择框的ListView,用setChoiceMode()方法设定选择为多选还是单选
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_checked, s));
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
android.R.layout.simple_list_item_multiple_choice:实现带CheckBox的ListView
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_multiple_choice, s));
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
android.R.layout.simple_list_item_single_choice:实现带RadioButton的ListView
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_single_choice, s));
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
ListView绑定监听器
//绑定监听器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(MainActivity.this, "你点击了第" + i + "行", Toast.LENGTH_SHORT).show();
}
});
2. ListView使用SimpleAdapter
使用simpleAdapter可以自定义ListView中的item的内容,比如图片等。下面的例子就用上了ImageView和TextView
例子
定义每一个item的布局
<?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="100dp"
android:layout_margin="10dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="20sp"/>
</LinearLayout>
修改MainActivity中的代码
public class MainActivity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过id找到listView对象
listView = findViewById(R.id.listView);
ArrayList<HashMap<String, Object>> listItem = new ArrayList<>();
for (int i = 0; i < 10; i++) {
HashMap<String, Object> map = new HashMap<>();
//加入图片
map.put("ItemImage", R.drawable.image);
map.put("ItemText", "这是第"+i+"行");
listItem.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this,
//绑定的数据
listItem,
//每一行的布局
R.layout.item,
//动态数组中的数据源的键映射到布局文件对应的控件中
new String[] {"ItemImage", "ItemText"},
new int[] {R.id.imageView, R.id.textView});
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(MainActivity.this, "你点击了第" + i + "行", Toast.LENGTH_SHORT).show();
}
});
}
}
使用SimpleAdapter的数据一般都是用HashMap构成的ArrayList,列表的每一项对应ListView的每一行。通过SimpleAdapter的构造函数,将HashMap的每个键的数据映射到布局文件中对应控件上。
步骤:
- 自定义ListView的每一个item的布局
- 定义一个HashMap构成的动态数组,数据以键值对的形式存储
- 创建一个适配器对象,有五个构造参数:上下文、每一个item的布局、HashMap的键、布局控件的id
- 将ListView绑定到SimpleAdapter上
3. ListView使用BaseAdapter、ListView的优化
修改item.xml代码,把ImageView改为Button
<?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"
android:layout_margin="10dp">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false"
android:focusable="false"
/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="20sp"/>
</LinearLayout>
BaseAdapter是一个抽象类,要写一个类继承它,下面代码自定义一个内部类MyAdapter继承BaseAdapter
MainActivity代码:
public class MainActivity extends AppCompatActivity {
private ListView listView;
ArrayList<HashMap<String, Object>> listItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过id找到listView对象
listView = findViewById(R.id.listView);
MyAdapter myAdapter = new MyAdapter(this);
listView.setAdapter(myAdapter);
//为ListView添加点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.v("MyListViewBase", "你点击了ListView条目" + i);
}
});
}
/**
* 获取数据的方法
* @return
*/
private ArrayList<HashMap<String, Object>> getDate() {
ArrayList<HashMap<String, Object>> list = new ArrayList<>();
//添加数据
for (int i = 0; i < 30; i++) {
HashMap<String, Object> map = new HashMap<>();
map.put("textView", "这是第" + i + "行");
list.add(map);
}
return list;
}
/**
* 新建一个MyAdapter类,继承BaseAdapter
*/
private class MyAdapter extends BaseAdapter {
//声明一个LayoutInflater对象用于导入布局
private LayoutInflater mInflater;
public MyAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return getDate().size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
//观察convertView随ListView滚动情况
Log.v("MyListViewBase", "getView" + i + " " + view);
if (view == null) {
view = mInflater.inflate(R.layout.item, null);
holder = new ViewHolder();
holder.button = view.findViewById(R.id.button);
holder.textView = view.findViewById(R.id.textView);
//绑定ViewHolder对象
view.setTag(holder);
} else {
//取出ViewHolder对象
holder = (ViewHolder) view.getTag();
}
//设置TextView显示的内容,即我们存放在动态数组中的数据
holder.textView.setText(getDate().get(i).get("textView").toString());
//为Button添加点击事件
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v("MyListViewBase", "你点击了按钮" + i);
}
});
return view;
}
}
public final class ViewHolder {
public Button button;
public TextView textView;
}
}
需要注意的是,在定义点击事件的时候,Button会抢夺ListView的焦点,需要将Button设置为没有焦点,在item.xml文件中,在Button里加入一行android:focusable="false"即可
参考文章:https://blog.csdn.net/xhbxhbsq/article/details/53487456