前几天,遇到了一个小问题,就是listview文件列表中的全选上传的时候,发现并不是全选了。很疑惑,自认为对listview的原理,探究以及adapter的自定义编写有些许了解了,最后明白了,在listview还有一个Recycler缓存机制,就是说在setAdapter后,getView方法返回的是可见的视图item,其他的item只有滚动到屏幕中来后才会执行getView的方法。这也就是为什么我的文件全选没有选到的原因了,就是我把全选写到getView中了。。。所以GG了
那么要怎么实现全选,反选呢,其实很简单,定义一个Boolean类型的数组,这是我们常规会想到的了,每一次的全选反选或者对checkbox操作就对相应位置的数组进行更改boolean值就可以了。但是这么搞确实有点麻烦啊,索性就在Bean里面做点文章,增加一个boolean的字段来标记。
看下ProductBean.java代码
package com.nst.Bean;
/**
* Created by zsj on 2016/7/21.
*/
public class ProductBean {
private int productId;
private String title;
private boolean chk;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isChk() {
return chk;
}
public void setChk(boolean chk) {
this.chk = chk;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
}
Adapter中的代码
package com.nst.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import com.nst.Bean.ProductBean;
import com.nst.com.hellowworld.R;
import java.util.List;
/**
* Created by zsj on 2016/7/21.
*/
public class ProductAdapter extends BaseAdapter {
private int mResource;
private Context mContext;
private List<ProductBean> mData;
//构造方法
public ProductAdapter(int LayoutId, Context mContext, List<ProductBean> mData) {
this.mContext = mContext;
this.mResource = LayoutId;
this.mData = mData;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
//是否可见
boolean isVisible = false;
public void setVisible(Boolean visible) {
isVisible = visible;
notifyDataSetChanged();
}
@Override
public View getView(final int position, View contentview, ViewGroup viewGroup) {
ViewHolder viewHolder = null;
if (contentview == null) {
viewHolder = new ViewHolder();
//动态加载布局
contentview = LayoutInflater.from(mContext).inflate(mResource, null);
viewHolder.tvTitle = (TextView) contentview.findViewById(R.id.tv_title);
viewHolder.chkMybox = (CheckBox) contentview.findViewById(R.id.chk_box);
contentview.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) contentview.getTag();
}
viewHolder.tvTitle.setText(mData.get(position).getTitle());
viewHolder.chkMybox.setChecked(mData.get(position).isChk());
viewHolder.chkMybox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mData.get(position).setChk(b);//更改List<bean>中的数据
}
});
if(isVisible){
viewHolder.chkMybox.setVisibility(View.VISIBLE);
}else{
viewHolder.chkMybox.setVisibility(View.GONE);
}
return contentview;
}
//容器
public class ViewHolder {
TextView tvTitle;
CheckBox chkMybox;
}
}
MainActivity中的代码:
package com.nst.com.hellowworld;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import com.nst.Bean.ProductBean;
import com.nst.adapter.ProductAdapter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MainActivity extends Activity implements View.OnClickListener {
private TextView tvOperate;
private ListView lvProduct;
private int[] subCount;
private List<String> data;
private ProductAdapter mAdapter;
private List<ProductBean> ListBean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}
private void initListener() {
}
private void initData() {
//获取系统时间
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = dateFormat.format(date);
data = new ArrayList<String>();
ListBean = new ArrayList<ProductBean>();
for (int i = 0; i < 20; i++) {
ProductBean bean = new ProductBean();
bean.setChk(false);
bean.setProductId(i);
bean.setTitle(i + "、" + time);
ListBean.add(bean);
}
mAdapter = new ProductAdapter(R.layout.product_items, MainActivity.this, ListBean);
lvProduct.setAdapter(mAdapter);
}
//全选或者全不选
public void selectAll(Boolean b) {
//遍历算法,相当于for循环
for (ProductBean bean : ListBean) {
bean.setChk(b);
}
mAdapter.notifyDataSetChanged();
}
//反选
public void selectopp() {
for (ProductBean bean : ListBean) {
bean.setChk(!bean.isChk());
}
mAdapter.notifyDataSetChanged();
}
private void initView() {
tvOperate = (TextView) findViewById(R.id.tv_op);
lvProduct = (ListView) findViewById(R.id.product_all);
tvOperate.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_op:
//显示checkbox
if (tvOperate.getText().equals("操作")) {
tvOperate.setText("全选");
mAdapter.setVisible(true);
} else if (tvOperate.getText().equals("全选")) {
tvOperate.setText("反选");
selectAll(true);
} else if (tvOperate.getText().equals("反选")) {
tvOperate.setText("隐藏");
selectopp();
} else if (tvOperate.getText().equals("隐藏")) {
tvOperate.setText("操作");
selectAll(false);//全不选
mAdapter.setVisible(false);
}
break;
}
}
}
xml文件就不贴出来了。。。就是个listview,然后那个item的布局文件也不贴了。。。最后效果图附上:
写这个小例子主要也是为了理解,主要是getView的方法返回的是我们屏幕中所看得见的item,返回的是view,然后第一次加载的时候,只会初始化能看见的8个item,可以打断点看到。。。你往下拖后,才继续执行第9个。。。以及后面的,这就是listview自带的缓存机制了,偷张图片给你们理解下:
demo下载地址。。。我觉得不需要啊,好虚啊,这么简单的demo,然后,我们也可以去了解下更强大的recyclerview。。。下次再来
总结下:好好码代码,哪怕是最简单的代码~
这里由这个demo的理解总结出一种算法:取出N个集合中的交集,首先将每个集合添加到一个新的集合中,将所有的标识设置为1,即首先设定每个集合中的元素重复了一次,依次遍历其他集合中的元素对大集合中的元素进行比对,更改那个1,即重复的次数,就可以算出所有集合中所有元素重复的次数。
番外篇:今天是个好日子,解决了一个一直困扰我的一个问题。就是在listview的复用布局的过程中,item中进行多选、单选、动画播放开关等操作的过程中会产生数据错乱的问题。这个问题产生的原因主要是listview的布局复用机制,一次只会生成一个屏幕的item数量,然后进行复用。其实解决的方案很简单,就是将布局和model关联起来,将这个状态值存到作为一个字段添加到model中。。。每次操作改变modle中的字段的状态。或者说,你有时候为了快速便捷用到了pojo直接转json,而服务端并不需要这个字段的话。那么我们可以专门为它建立一个实体类model记录每个条目的状态。然后每次滚动到对应的item的时候,都会执行getview的方法,再将model中对应的值赋值给它。那么你的item中假设有多选框,音乐播放列表动画,单选框的时候,点击那个时间,改变model中的值,我想这也是MVC的思想吧。把Model和View分离开来,真的很奇妙~have a nice day