Android 结合实际项目学会ListView局部刷新和相关知识《一》
转载本专栏博客,请注明出处:道龙的博客
最近在公司参与的项目中有一个界面需要做局部UI更新处理,把其化烦为简为Demoi形式写在这里。我们还是运行该Demo,知道ListView局部刷新的使用场景:(受时间限制,本篇就介绍这么多功能,下一篇会在这个Demo中加入更多的功能)
可以看到,点击每个Item的时候,ListView上的CheckBox会选中或取消选中。这里面用到知识点就是ListView的局部刷新,局部的意思就是脱离ListView,在每个Item位置进行更新UI操作。那么就从头一步步的学习如何实现这个功能:
一、实现基本功能。
模拟数据源,把最基本的功能先跑起来:
布局、自定义样式、自定义选择器都很简单,过多的代码就不再写了,文章只贴出业务逻辑重要的代码(文章最后会给出源代码可自行下载;由于实习公司使用的IDE还是Eclipse,本篇是基于eclipse写的)
主活动中代码也很常规简单:
public class MainActivity extends Activity { private ListView mListView; List<ItemBean> mDatas = new ArrayList<ItemBean>(); private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.listview); initData(); adapter = new MyAdapter(); mListView.setAdapter(adapter); } /**模拟数据*/ private void initData() { ItemBean mItemBean = null; for (int i = 0; i < 40; i++) { //集合添加20个对象 mItemBean = new ItemBean(); mItemBean.setText("学习ListView局部刷新"+i); mItemBean.setResIcon(R.drawable.directory_icon); mDatas.add(mItemBean); } } private class MyAdapter extends BaseAdapter{ @Override public int getCount() { if(mDatas != null){ return mDatas.size(); } return 0; } @Override public Object getItem(int position) { if(mDatas != null){ return mDatas.get(position); } return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ holder = new ViewHolder(); convertView = View.inflate(getApplicationContext(), R.layout.file_item, null); holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon); holder.tvText = (TextView) convertView.findViewById(R.id.tv_name); holder.ivOption = (ImageView) convertView.findViewById(R.id.iv_option); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } //拿到数据 ItemBean mItem = (ItemBean) getItem(position); //设置数据 holder.ivIcon.setImageResource(mItem.getResIcon()); holder.tvText.setText(mItem.getText()); return convertView; } class ViewHolder{ ImageView ivIcon; TextView tvText; ImageView ivOption; } } }此时运行程序:
接下来就对上边的常规代码做一下修饰了:
二、进入编辑模式
我们长按item的时候,希望整个布局改变一下进入编辑模式,让复选框图标展示,对应位置上ImageView图标消失,就可以这么写。
首先写一个方法,来控制布局的改变:
private boolean isEdit; /**开始编辑模式*/ private void startEditMode() { isEdit = true;//标志位置为true //进入编辑模式,要改变IListView的界面 adapter.notifyDataSetChanged(); } /**结束编辑模式*/ private void stopEditMode(){ isEdit = false; }
然后加入长按item的点击事件:
mListView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { startEditMode(); return true;//返回true后,mListView.setOnItemClickListener就不会再去调用 } });
三、ListView中CheckBox选中取消,实现局部的刷新
定义一个item局部刷新的方法:
/**定义一个item局部刷新的方法*/ public void updateItemView(View ItemView){ CheckBox itemCb = (CheckBox) ItemView.findViewById(R.id.cb_checkbox); if(itemCb.isChecked()){ //点击item,从选中状态调到未选中状态 itemCb.setChecked(false); }else{ itemCb.setChecked(true); } }
在item的点击事件的时候,调用这个方法,即可完成checkbox的选中与取消:
mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if(isEdit){ //如果是编辑模式 adapter.updateItemView(view); }else{ //不是编辑模式,点击item做其他逻辑处理 Toast.makeText(getApplicationContext(), "当前item"+position, 0).show(); } } });目前我们仅仅是实现了界面的刷新,但是cb的选中与取消要记录起来,点击了哪个item也要记录起来,这样才能做接下来的操作,选中cb执行什么样的任务,因此我们需要使用javabean,记录每次点击选中cb的操作:
具体的局部刷新修改后的方法如下:
/**定义一个item局部刷新的方法*///position,为了拿到当前item的对象,记录状态 public void updateItemView(View ItemView,int position){ position = position - mListView.getHeaderViewsCount(); ItemBean itemBean = mDatas.get(position); CheckBox itemCb = (CheckBox) ItemView.findViewById(R.id.cb_checkbox); if(itemCb.isChecked()){ //点击item,从选中状态调到未选中状态 itemCb.setChecked(false); //记录当前item未选中状态 itemBean.setChecked(false); }else{ itemCb.setChecked(true); //记录当前item选中状态 itemBean.setChecked(true); } //通过集合把选中的item的对象itemBean记录起来 List<ItemBean> selectDatas = new ArrayList<ItemBean>(); for (ItemBean info : mDatas) { if(info.isChecked()){//当前的item是选中的 selectDatas.add(info); } } /**测试局部刷新*/ for (ItemBean itemBean2 : selectDatas) { System.out.println(itemBean2.getText()); } }然后该方法肯定要被调用咯,在哪里调用?点击item的时候嘛,那就在注册item的点击事件稍作修改就可以了:
mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if(isEdit){ //如果是编辑模式 adapter.updateItemView(view,position); }else{ //不是编辑模式,点击item做其他逻辑处理 Toast.makeText(getApplicationContext(), "当前item"+position, 0).show(); } } });
但是这个时候还是有许多问题的,比如第二页的数据会复用第一页的数据,那就先解决这个bug。
只需要在getView里面,对item上边的cb重新复制就可以了。
if(isEdit){//是编辑模式 // Ui层面进入编辑模式 holder.checkBox.setVisibility(View.VISIBLE); holder.ivOption.setVisibility(View.GONE); /**解决复用问题,对每一个item上的cb都重新赋值*/ if (mItem.isChecked()) { holder.checkBox.setChecked(true); } else { holder.checkBox.setChecked(false); } }else{ holder.checkBox.setVisibility(View.GONE); holder.ivOption.setVisibility(View.VISIBLE); }
四、根据是否编辑状态,修改顶部标题栏文本信息
接下来的逻辑稍微复杂,就是通过当前状态,来修改顶端的标题栏状态。
首先,长按进入编辑模式的时候,要显示当前选中多少个。需要一个标志位mSelectedCount。进入编辑模式,显示标题:
//修改标题栏 mTextView.setText(String.format("已选择了%d个", mSelectedCount));
那对于标志的增加减少要放到,updateItemView里面
if(itemCb.isChecked()){ //点击item,从选中状态调到未选中状态 itemCb.setChecked(false); //记录当前item未选中状态 itemBean.setChecked(false); mSelectedCount --; }else{ itemCb.setChecked(true); //记录当前item选中状态 itemBean.setChecked(true); mSelectedCount ++; }由于逻辑稍微复杂,也不是要介绍局部刷新这个技术点的范围了,就不再继续往下写了。我把Demo全部代码,打包上传了。可以直接去下载,学习。看看一下后边的复杂逻辑是如何实现的:
明天或者后天加入更多功能后,再把资源上传吧,今天就到这里了~