简单的ListView用法
ArrayAdapter
- ArrayAdapter是只包含字符串的一个简单适配器
- 首先在在布局文件中添加ListView控件
- 然后在代码实例化适配器,同时指定listview中内容的布局方式和要显示的内容,最后为listview添加监听事件
public class MainActivity extends AppCompatActivity {
private ListView list;
//设置字符串数组存储要在列表中显示的内容
private String[] data={"Apple","nihao","shijie","Apple","nihao","shijie","Apple","nihao","shijie","Apple","nihao","shijie","Apple",
"nihao","shijie","Apple","nihao","shijie","Apple","nihao","shijie","Apple","nihao","shijie","Apple","nihao","shijie"};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list= (ListView) findViewById(R.id.listView);
//创建最常用的ArrayAdapter实例,第一个参数当前上下文,第二个参数ListView子项布局的id,第三个参数是适配的数据
//android.R.layout.simple_list_item_1是android系统内置的布局文件
ArrayAdapter<String> adapter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,data);
list.setAdapter(adapter);
//为listView添加监听事件
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String str=(String)list.getItemAtPosition(position);
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
}
});
}
}
- 效果如图所示:
SimpleAdapter
- SimpleAdapter是扩展性很好的一个适配器,我们可以条目的布局细节,然后再将数据和布局文件中的控件一一对应即可。
- 比如这样的布局
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:id="@+id/imageView" />
</LinearLayout>
- 逻辑代码如下
public class MainActivity extends AppCompatActivity {
private ListView listView;
private List<Map<String,Object>> datalist2;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
SimpleAdapter adapter1=new SimpleAdapter(this,datalist2,R.layout.layout_simpleadapter,new String[]{"icon","text"},new int[]{R.id.imageView,R.id.textView});
listView.setAdapter(adapter1);
}
private void init() {
listView= (ListView) findViewById(R.id.listView);
datalist2=new ArrayList<>();
for (int i=0;i<50;i++){
Map<String,Object> map=new HashMap<>();
map.put("icon",R.mipmap.ic_launcher);
map.put("text",i+"条数据" );
datalist2.add(map);
}
}
}
- 重点注意此处
SimpleAdapter adapter1=new SimpleAdapter(this,datalist2,R.layout.layout_simpleadapter,new String[]{"icon","text"},new int[]{R.id.imageView,R.id.textView});
- 第二个参数自定义的布局文件
- 第三个参数,添加的数据对应的键的值
- 第四个参数于第三个参数务必一一对应,第四个参数放置他们对应的id
SimpleAdapter相比于自定义的Adapter的区别
SimpleAdapter不用再自己写adapter中的各个方法的实现,只需要将SimpleAdapter实例化出来就可以了
同样也由于不用自己写adapter中的各个方法的实现,所以我们无法对lsitview实现效率优化。
定制ListView的界面
- 既然要自定义listview的界面,首先新建布局文件,将布局按自己要求写好
<?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">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:id="@+id/imageView" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="@+id/textView" />
</LinearLayout>
- 新建一个工具类,用来存放每个条目中个空间信息,如这个条目中图片的id和文本的内容
package com.lingzhuo.applist;
/**
* Created by Wang on 2016/3/17.
*/
public class App {
private String name;
private int picId;
public App(String name, int picId) {
this.name = name;
this.picId = picId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPicId() {
return picId;
}
public void setPicId(int picId) {
this.picId = picId;
}
}
- 由于是自定义listview控件,所以系统自带的适配器就无法完成适配,因此必去自己重写适配器和其中的方法
public class MyAdapter extends ArrayAdapter<App> {
private int layoutId;
//textViewResourceId条目布局文件的id
public MyAdapter(Context context, int textViewResourceId, List<App> objects) {
super(context,textViewResourceId, objects);
layoutId=textViewResourceId;
}
//每当listview滚动的时候,每有一个新的条目进入屏幕范围,就会调用一次这个方法
public View getView(int position, View convertView, ViewGroup parent) {
App app=getItem(position);
//加载定义的条目的布局文件
View view= LayoutInflater.from(getContext()).inflate(R.layout.item_layout,null);
ImageView imageView= (ImageView) view.findViewById(R.id.imageView);
TextView textView= (TextView) view.findViewById(R.id.textView);
imageView.setImageResource(app.getPicId());
textView.setText(app.getName());
return view;
}
}
- 适配器定义完毕,就需要在主布局中加入listview控件,并得到它,实例化自己的适配器,将适配器与listview绑定到一起就可以了,还可以对listview添加点击监听事件
public class MainActivity extends AppCompatActivity {
private ListView listView;
private List<App> applist=new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
listView= (ListView) findViewById(R.id.listView);
//实例化自己定义的适配器
final MyAdapter adapter=new MyAdapter(getApplicationContext(),R.layout.item_layout,applist);
listView.setAdapter(adapter);
//添加监听事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
App app= (App) listView.getItemAtPosition(position);
Toast.makeText(MainActivity.this, app.getName(), Toast.LENGTH_SHORT).show();
}
});
}
//初始化条目的各种显示信息
private void init() {
App qq=new App("QQ",R.drawable.qq);
applist.add(qq);
App as=new App("AS",R.drawable.as);
applist.add(as);
App baidu=new App("baidu",R.drawable.baidu);
applist.add(baidu);
App dream=new App("dream",R.drawable.dream);
applist.add(dream);
App eclipse=new App("eclipse",R.drawable.eclipse);
applist.add(eclipse);
App gy=new App("gy",R.drawable.gy);
applist.add(gy);
App music=new App("music",R.drawable.music);
applist.add(music);
App pot=new App("pot",R.drawable.pot);
applist.add(pot);
App vs=new App("vs",R.drawable.vs);
applist.add(vs);
applist.add(qq);
applist.add(as);
applist.add(baidu);
applist.add(dream);
applist.add(eclipse);
applist.add(gy);
applist.add(music);
applist.add(pot);
applist.add(vs);
}
}
- 效果图如下:
ListView的效率优化
- 在getView(int position, View convertView, ViewGroup parent)方法中,还有一个convertView参数,这个参数用于将之前加载好的进行缓存,以便之后可以重用
- 简单说就是,滚动list的时候,convertView就是那个滚出屏幕的条目,这个条目可以复用,用来显示正在进入屏幕的那个条目,这样就避免了一直创建view,可以提高效率
public View getView(int position, View convertView, ViewGroup parent) {
App app=getItem(position);
View view;
//判断convertView,为空就加载布局文件,
if (convertView==null){
view= LayoutInflater.from(getContext()).inflate(R.layout.item_layout,null);
}else{
view=convertView;
}
ImageView imageView= (ImageView) view.findViewById(R.id.imageView);
TextView textView= (TextView) view.findViewById(R.id.textView);
imageView.setImageResource(app.getPicId());
textView.setText(app.getName());
return view;
}
- 上面的代码虽然不会在重复加载布局文件了,但在每次getView()中还是会调用findViewById()方法来获取一次控件的实例。所以我们可以使用ViewHolder来对这部分进行优化
public View getView(int position, View convertView, ViewGroup parent) {
App app=getItem(position);
View view;
ViewHolder viewHolder;
//判断convertView,为空就加载布局文件,同时对view和viewHolder进行实例化
if (convertView==null){
view= LayoutInflater.from(getContext()).inflate(R.layout.item_layout,null);
viewHolder=new ViewHolder();
viewHolder.imageView=(ImageView) view.findViewById(R.id.imageView);
viewHolder.textView=(TextView) view.findViewById(R.id.textView);
//将viewHolder存储在view中
view.setTag(viewHolder);
}else{
//若不为空,直接进行复用view和viewHolder
view=convertView;
viewHolder= (ViewHolder) view.getTag();
}
//在对viewHolder中的控件进行赋值即可
viewHolder.imageView.setImageResource(app.getPicId());
viewHolder.textView.setText(app.getName());
return view;
}
//新建一个内部类,在这个类中,定义在条目中每个空间的实例
class ViewHolder{
ImageView imageView;
TextView textView;
}
在此基础上制作的界面
注意,在list中添加了checkbox,button等这种控件后,list的点击事件会失效,具体原因是因为发生了焦点抢夺,只需要我们对checkbox、button等控件添加android:focusable=”false”这个属性,就可以解决焦点抢夺的问题了