ListView控件功能全解析

365彩票app下载2020 📅 2025-08-17 12:20:56 ✍️ admin 👀 3351 ❤️ 947
ListView控件功能全解析

ListView是Android手机系统中使用非常频繁的控件,以垂直列表的形式显示数据项,ListView的用法也较为复杂,下面将详细介绍ListView相关的各种用法。

1、创建使用ListView

有2种方式创建ListView

在布局文件中使用ListView创建

android:id="@+id/list"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

在代码中获取到实例后为ListView设置Adapter

listView = (ListView)findViewById(R.id.list);

listView.setAdapter(adapter);

Activity继承ListActivity

继承ListActivity后,不需要设置布局文件,直接使用setListAdapter()为ListView设置Adapter即可

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setListAdapter(adapter);

}

2、自定义ListView的item格式

新建布局文件item.xml,代码如下:

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:gravity="center"

android:textColor="#F00"

android:textSize="16sp"/>

将文字设为居中显示,设置了文本的颜色和大小,构造Adapter时将布局文件传入

ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item, datas);

listView.setAdapter(adapter);

3、设置ListView的点击事件

为ListView的item设置点击事件

listView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view,

int position, long id) {

// TODO Auto-generated method stub

Toast.makeText(MainActivity.this, "Item " + datas.get(position) + " clicked", Toast.LENGTH_LONG).show();

}

});

运行程序,点击列表项

4、ListView数据改变,更新ListView

修改ListView的点击事件,点击item后删除List中的数据项,数据改变后,页面不会自动刷新,需要调用adapter的notifyDataSetChanged()方法通知列表更新

listView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view,

int position, long id) {

// TODO Auto-generated method stub

Toast.makeText(MainActivity.this, "Item " + datas.get(position) + " deleted", Toast.LENGTH_LONG).show();

datas.remove(position);

adapter.notifyDataSetChanged();

}

});

运行程序,点击任意列表项

5、ListView显示多种类型的item

上面的例子都是显示的一个类型的列表项,只包含一个TextView,有时会需要显示几种不同的item,包含图片、文本、按钮等元素,这就需要为ListView定义几个不同的布局文件,一个布局文件代表一种类型的item

布局文件item1.xml

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentLeft="true"

android:layout_centerVertical="true"

android:src="@drawable/ic_launcher"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textSize="20sp"/>

布局文件item2

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textSize="20sp"/>

布局文件item3

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textSize="20sp"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentRight="true"/>

布局文件1中定义了一个ImageView和一个TextView,布局文件2中只有一个TextView,布局文件3中定义了一个TextView和一个CheckBox,下面是MainActivity.java文件

public class MainActivity extends Activity {

ListView listView;

List datas = new ArrayList();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

listView = (ListView)findViewById(R.id.list);

initData();

adapter = new ArrayAdapter(this, R.layout.item, datas);

listView.setAdapter(new ListAdapter());

}

class ListAdapter extends BaseAdapter {

public final int TYPE_1 = 0;

public final int TYPE_2 = 1;

public final int TYPE_3 = 2;

@Override

public int getCount() {

// TODO Auto-generated method stub

return datas.size();

}

@Override

public long getItemId(int position) {

// TODO Auto-generated method stub

return position;

}

@Override

public Object getItem(int position) {

// TODO Auto-generated met hod stub

return datas.get(position);

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

// TODO Auto-generated method stub

int viewType = getItemViewType(position);

View view = null;

TextView text = null;

switch(viewType) {

case TYPE_1:

view = View.inflate(MainActivity.this, R.layout.item1, null);

text = (TextView)view.findViewById(R.id.text1);

break;

case TYPE_2:

view = View.inflate(MainActivity.this, R.layout.item2, null);

text = (TextView)view.findViewById(R.id.text2);

break;

case TYPE_3:

view = View.inflate(MainActivity.this, R.layout.item3, null);

text = (TextView)view.findViewById(R.id.text3);

break;

}

text.setText(datas.get(position) + "");

return view;

}

@Override

public int getViewTypeCount() {

// TODO Auto-generated method stub

return 3;

}

@Override

public int getItemViewType(int position) {

// TODO Auto-generated method stub

if(position < 5) {

return TYPE_1;

} else if(position < 10) {

return TYPE_2;

} else {

return TYPE_3;

}

}

}

public void initData() {

for(int i = 1; i <= 10; i++) {

datas.add(i + "");

}

}

}

重写BaseAdapter的getViewTypeCount()和getItemViewType()方法,定义了3种不同的布局,getViewTypeCount中返回item类型的数目,在getItemViewType中根据位置返回布局类型,getView中根据不同的type加载不同的布局文件,最后,将Adapter设置到ListView中

运行效果:

6、ListView显示优化

ListView在使用过程经常会遇到滑动卡顿的性能问题,所以如何优化ListView的加载就显得尤为重要,ListView的性能优化主要包括几个方面

1、利用convertView复用之前的缓存布局,减少加载布局的次数

ListView在滚动的过程中,每加载一个View都会重新加载一遍布局文件,如果ListView中的条目非常多,在快速滑动时,就会导致列表卡顿。在getView()方法中有一个convertView参数,向上滑动列表时,隐藏的view会缓存在这个convertView中,新显示的view可以复用隐藏的convertView,这样就不会每次都加载一遍布局

示例代码

@Override

public View getView(int position, View convertView, ViewGroup parent) {

// TODO Auto-generated method stub

if(convertView == null) {

convertView = View.inflate(MainActivity.this, R.layout.item, null);

}

TextView text = (TextView)convertView.findViewById(R.id.text1);

text.setText(datas.get(position));

return convertView;

}

在加载布局时,判断convertView是否为空,为空时再去加载布局文件,这样能最大的减少加载布局的次数,提升效率

2、使用自定义ViewHolder类,减少findViewById的次数

在解析布局文件查找控件时,需要不断的解析每个节点,如果可以减少查找控件的时间,会对ListView的加载性能提升不少。

示例代码

@Override

public View getView(int position, View convertView, ViewGroup parent) {

// TODO Auto-generated method stub

ViewHolder viewHolder;

if(convertView == null) {

viewHolder = new ViewHolder();

convertView = View.inflate(MainActivity.this, R.layout.item, null);

viewHolder.textView = (TextView)convertView.findViewById(R.id.text);

convertView.setTag(viewHolder);

} else {

viewHolder = (ViewHolder)convertView.getTag();

}

viewHolder.textView.setText(datas.get(position));

return convertView;

}

//自定义ViewHolder类

class ViewHolder {

TextView textView; //定义item中显示的所有控件

}

在第一次创建View的时候,查找到item中的控件,并存储到ViewHolder类中,通过setTag()方式将ViewHolder设置到convertView中,下次再加载View的时候直接从convertView中获取

3、利用ListView的分页加载功能,一次只加载一页条目

如果ListView的条目相当多,在显示ListView的时候一次把所有的条目全部加载完,势必会很耗时间,也会导致列表相响应慢,这时可以考虑来分批加载数据

下面利用ListView的OnScrollListener接口实现ListView的滑动加载功能

主布局文件只有一个ListView

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.example.testlistview.MainActivity" >

android:id="@+id/list"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

在列表底部有一个Button,点击Button可以加载更多条目,向上滑动到底部也会自动加载更多条目,加载时Button隐藏,需要显示一个加载的进度条

底部布局文件

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/load"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="加载更多"/>

android:id="@+id/load_progress"

android:layout_width="wrap_content"

android:layout_height="20dp"

android:orientation="horizontal"

android:layout_gravity="center"

android:visibility="gone">

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="正在加载..."/>

ListView的滑动加载功能需要实现OnScrollListener接口,滑动加载只关注静止时的状态,当ListView滑动到最底部并且可见的条目数等于adapter的数目,自动加载。当加载的条目和最大条目数相等时,移除底部的View,同时在提示用户没有更多数据可以加载了

MainActivity.java

public class MainActivity extends ActionBarActivity {

ListView listView;

View footerView;

Button load;

View loadProgress;

List datas = new ArrayList();

ArrayAdapter adapter;

public final int MAX_NUM = 50; //最大的条目数

int lastVisibleItem; //最后一个可见的item

Handler handler = new Handler();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

listView = (ListView)findViewById(R.id.list);

footerView = getLayoutInflater().inflate(R.layout.load_more, null);

load = (Button)footerView.findViewById(R.id.load);

loadProgress = footerView.findViewById(R.id.load_progress);

initData();

listView.addFooterView(footerView); //将底部布局添加到ListView中

adapter = new ArrayAdapter(this, R.layout.item, datas);

listView.setAdapter(adapter);

listView.setOnScrollListener(new OnScrollListener() {

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// TODO Auto-generated method stub

lastVisibleItem = firstVisibleItem + visibleItemCount -1;

//数据加载完毕,移除底部View

if(totalItemCount == MAX_NUM + 1) {

listView.removeFooterView(footerView);

Toast.makeText(MainActivity.this, "没有更多数据可加载", Toast.LENGTH_LONG).show();

}

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

// TODO Auto-generated method stub

//当滑动状态为静止并且可见条目数目等于adapter的数目时,加载条目

if(scrollState == OnScrollListener.SCROLL_STATE_IDLE && lastVisibleItem == adapter.getCount()) {

load.setVisibility(View.GONE);

loadProgress.setVisibility(View.VISIBLE);

handler.post(new Runnable() {

public void run() {

loadData();

adapter.notifyDataSetChanged();

load.setVisibility(View.VISIBLE);

loadProgress.setVisibility(View.GONE);

};

});

}

}

});

load.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

//加载更多数据

}

});

}

public void loadData() {

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

int count = adapter.getCount();

for(int i = count + 1; i < count + 6; i++) {

datas.add(i + "");

}

}

public void initData() {

for(int i = 1; i <= 15; i++) {

datas.add(i + "");

}

}

}

在代码中为listView添加了滚动监听,主要是实现OnScrollListener接口中的两个方法:onScroll()和onScrollStateChange(),在onScroll方法中计算最后一个可见条目的索引,在onScrollStateChanged中判断滑动状态,如果是静止状态,并且并且最后一个可见条目的索引等于adapter中的条目数,这时开始加载数据。

运行程序

ListView初始化时显示15条数据,向上滑动ListView

在程序中,启动一个线程,线程中等待3秒模拟耗时加载数据,每次加载5条数据,50条数据加载完毕后,底部View被移除,再继续向上滑动时,会给出提示,没有更多数据可以加载

7、ListView的选中模式

ListView具有4种选中模式:

ListView.CHOICE_MODE_NONE:默认模式ListView.CHOICE_MODE_SINGLE:单选模式ListView.CHOICE_MODE_MULTIPLE:多选模式,无排除性,会响应onClick事件ListView.CHOICE_MODE_MULTIPLE_MODAL:多选模式,有排除性,不响应onClick事件

ListView的默认模式为不会选中任何一个列表项,单选模式只能选中一个列表项,多选模式可以选中多个列表项,ListView默认不会选中任何项

选中的列表项被存在一个SparseBooleanArray中,存储的方式为键值对存储,键存储的是item的索引,值为选中的状态,true或者false,默认模式下SparseBooleanArray为空,单选模式下存的是选中的item项,多选模式下存储所有选中过的项及选中状态

设置ListView为单选模式,在ListView的OnItemClick事件中获取列表项的选择状态

listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

listView.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView parent, View view,

int position, long id) {

// TODO Auto-generated method stub

SparseBooleanArray array = listView.getCheckedItemPositions();

for(int i = 0; i < array.size(); i++) {

Log.i(TAG, "选中项:" + array.keyAt(i) + ",选中状态:" + array.get(array.keyAt(i)));

}

}

});

点击多个列表项

我按顺序点击了1到4的列表项,从打印的log看出SparseBooleanArray中只保存了一个选中的item状态

修改ListView的选中模式为多选模式

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

运行程序,依次点击1-3的列表项

从log中看出,点击第一个列表项时,SparseBooleanArray中只保存了一条数据,点击多个列表项,会在SparseBooleanArray中保存所有点击过的item,再次点击1-3的列表项

再次点击选中的item项,SparseBooleanArray中依然保存点击过的列表项,只是把选中状态置为了false

根据ListView多选状态的特性,可以在开发过程中遇到需要突出显示选中列表项的时候,利用item的选中状态来改变选中item的颜色,下篇博客中包含这个例子和ListView的另一个多选状态

ListView的两种多选模式:http://blog.csdn.net/zh175578809/article/details/72802461

相关推荐

bt365最快线路检测 开放世界生存游戏《人渣》1.0正式版现已发售
365彩票app下载2020 精通 iPhone 截屏:捕获、编辑、分享!
bt365最快线路检测 高帮鞋配什么裤子 高帮帆布鞋这样穿,显高到尖叫!
365bet备用器 [血法]【115版本:职业百科】COLG全职业百科一一猩红法师(更新至周年庆版本)
365彩票app下载2020 猎魂觉醒公测时间

猎魂觉醒公测时间

📅 08-17 👀 6520
365彩票app下载2020 体彩世界杯赔率是多少,体彩世界杯规则中奖规则
365bet备用器 iPhone 6s怎么越狱

iPhone 6s怎么越狱

📅 07-24 👀 8521
365彩票app下载2020 穿越火线怎么选区?(cf端游怎么选区)
bt365最快线路检测 最好的大樱桃品种有哪些?

友情伙伴