ListView——“点赞”状态屏幕滑动数据解决方法
我们在使用ListView时候,可能一行数据有名次、头像、昵称、补充文字/数据说明、“点赞”人数及图标,如下图“微信运动界面”所示。
而当我们有较多行数据,需要滑动屏幕时,这些“点赞”图标的选择状态就会错乱。还是以上图为例,假如当前设备的屏幕可以显示6行数据,总共需要显示9行数据;我们点赞了第1个好友,但是没有显示出来的第7个好友的点赞图标却变“红”了。这就是数据错乱问题,那么我们应该如何解决呢?
请看我下面的例子(在下面的Demo中,“点赞”图标我换成了可以更换背景色的Button,红色代表已经点赞了)。首先,我们先来看关键代码:
private class PlatformWithStateChangeAdapter extends BaseAdapter{
LayoutInflater mLayoutInflater = null;
public PlatformWithStateChangeAdapter(Context context) {
this.mLayoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return itemInfoList.size();
}
@Override
public Object getItem(int position) {
return null != itemInfoList ? itemInfoList.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final ItemInfo itemInfo = (ItemInfo) getItem(position);
if (convertView == null){
holder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.activity_button_state_change_list,null);
holder.img = (ImageView) convertView.findViewById(R.id.ivImg_btnstatechange);
holder.title = (TextView) convertView.findViewById(R.id.tvTitle_btnstatechange);
holder.info = (TextView) convertView.findViewById(R.id.tvInfo_btnstatechange);
holder.btnIsSelected = (Button) convertView.findViewById(R.id.btnDetail_btnstatechange);
final ViewHolder finalHolder = holder;
holder.btnIsSelected.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ItemInfo itemDetails = (ItemInfo) finalHolder.btnIsSelected.getTag();
if (itemDetails.isSelected()){
finalHolder.btnIsSelected.setBackgroundResource(R.color.green);
itemDetails.setSelected(false);
}
else {
finalHolder.btnIsSelected.setBackgroundResource(R.color.red);
itemDetails.setSelected(true);
}
}
});
convertView.setTag(holder);
holder.btnIsSelected.setTag(itemInfo);
}
else {
holder = (ViewHolder) convertView.getTag();
holder.btnIsSelected.setTag(itemInfo);
}
//避免滑屏时出现数据错乱重复
if (itemInfo.isSelected()){
holder.btnIsSelected.setBackgroundResource(R.color.red);
}
else {
holder.btnIsSelected.setBackgroundResource(R.color.green);
}
holder.img.setImageResource(itemInfo.getImg());
holder.title.setText(itemInfo.getTitle());
holder.info.setText(itemInfo.getInfo());
return convertView;
}
}
我们来看一下运行效果:
全部代码:
ButtonStateChangeActivity.java
package com.example.administrator.listviewdemo;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/9/4.
*/
public class ButtonStateChangeActivity extends AppCompatActivity{
ListView lvPlatforms = null;
List<ItemInfo> itemInfoList = null;
PlatformWithStateChangeAdapter platformWithStateChangeAdapter = null;
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button);
itemInfoList = getData();
lvPlatforms = (ListView) findViewById(R.id.lvPlatforms);
platformWithStateChangeAdapter = new PlatformWithStateChangeAdapter(this);
lvPlatforms.setAdapter(platformWithStateChangeAdapter);
ActionBar actionbar = getSupportActionBar();
actionbar.setTitle(R.string.actionBarTitle_btnstatechange);
actionbar.setDisplayHomeAsUpEnabled(true);
actionbar.setDisplayShowHomeEnabled(true);
}
private List<ItemInfo> getData(){
List<ItemInfo> itemInfos = new ArrayList<>();
ItemInfo itemInfo = new ItemInfo("Android01","I am Android!",R.mipmap.ic_launcher,false);
itemInfos.add(itemInfo);
itemInfo = new ItemInfo("Apple01","I am Apple!",R.mipmap.apple02,false);
itemInfos.add(itemInfo);
return itemInfos;
}
private final class ViewHolder{
private ImageView img;
private TextView title;
private TextView info;
private Button btnIsSelected;
}
private class PlatformWithStateChangeAdapter extends BaseAdapter{
LayoutInflater mLayoutInflater = null;
public PlatformWithStateChangeAdapter(Context context) {
this.mLayoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return itemInfoList.size();
}
@Override
public Object getItem(int position) {
return null != itemInfoList ? itemInfoList.get(position) : null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final ItemInfo itemInfo = (ItemInfo) getItem(position);
if (convertView == null){
holder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.activity_button_state_change_list,null);
holder.img = (ImageView) convertView.findViewById(R.id.ivImg_btnstatechange);
holder.title = (TextView) convertView.findViewById(R.id.tvTitle_btnstatechange);
holder.info = (TextView) convertView.findViewById(R.id.tvInfo_btnstatechange);
holder.btnIsSelected = (Button) convertView.findViewById(R.id.btnDetail_btnstatechange);
final ViewHolder finalHolder = holder;
holder.btnIsSelected.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ItemInfo itemDetails = (ItemInfo) finalHolder.btnIsSelected.getTag();
if (itemDetails.isSelected()){
finalHolder.btnIsSelected.setBackgroundResource(R.color.green);
itemDetails.setSelected(false);
}
else {
finalHolder.btnIsSelected.setBackgroundResource(R.color.red);
itemDetails.setSelected(true);
}
}
});
convertView.setTag(holder);
holder.btnIsSelected.setTag(itemInfo);
}
else {
holder = (ViewHolder) convertView.getTag();
holder.btnIsSelected.setTag(itemInfo);
}
//避免滑屏时出现数据错乱重复
if (itemInfo.isSelected()){
holder.btnIsSelected.setBackgroundResource(R.color.red);
}
else {
holder.btnIsSelected.setBackgroundResource(R.color.green);
}
holder.img.setImageResource(itemInfo.getImg());
holder.title.setText(itemInfo.getTitle());
holder.info.setText(itemInfo.getInfo());
return convertView;
}
}
final int updateMenuItemId = 100;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem updateMenuItem = menu.add(0,updateMenuItemId,0,"刷新");
updateMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case updateMenuItemId:
refresh();
platformWithStateChangeAdapter.notifyDataSetChanged();
break;
case android.R.id.home:
finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private Context getContext(){
return this;
}
private void refresh(){
ItemInfo itemInfo = new ItemInfo("Android02","I am Android!02",R.mipmap.ic_launcher,false);
itemInfoList.add(itemInfo);
itemInfo = new ItemInfo("Apple02","I am Apple!02",R.mipmap.ic_launcher,false);
itemInfoList.add(itemInfo);
}
}
package com.example.administrator.listviewdemo;
/**
* Created by Administrator on 2016/9/4.
*/
public class ItemInfo {
private int img;
private String title;
private String info;
private boolean selected;
public ItemInfo(String title,String info,int img,boolean selected){
this.title = title;
this.info = info;
this.img = img;
this.selected = selected;
}
public int getImg() {
return img;
}
public String getTitle() {
return title;
}
public String getInfo() {
return info;
}
public boolean isSelected() {
return selected;
}
public void setImg(int img) {
this.img = img;
}
public void setTitle(String title) {
this.title = title;
}
public void setInfo(String info) {
this.info = info;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
res/layout/activity_button_state_change_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lvatybtnstatechange"
xmlns:tools="http://schemas.android.com/tools"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.administrator.listviewdemo.ListActivityDemo">
<ImageView
android:layout_alignParentLeft="true"
android:id="@+id/ivImg_btnstatechange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!--需要要id,否则app停止运行-->
<RelativeLayout
android:layout_toRightOf="@+id/ivImg_btnstatechange"
android:paddingLeft="10dp"
android:id="@+id/button_aty_content_btnstatechange"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:textStyle="bold"
android:textSize="16sp"
android:id="@+id/tvTitle_btnstatechange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!--android:maxEms 单位为int类型-->
<TextView
android:layout_below="@+id/tvTitle_btnstatechange"
android:id="@+id/tvInfo_btnstatechange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
<Button
android:layout_alignParentRight="true"
android:text="点赞"
android:background="@drawable/btn_like"
android:id="@+id/btnDetail_btnstatechange"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
ListView——CheckBox状态屏幕滑动数据错误解决方法
之前我们小组在做一个项目,叫信号检测,主要用于检测运营商信号强度、用户可以截屏并查看截屏记录。其中用到ListView来展示截屏结果,我们的app为已经截屏的全部记录的每一行数据(截屏)都提供一个CheckBox,用户可以勾选当前截屏图标删除,先看一下整体的效果:
在这里也有个坑,当前我们截屏结果较多时(比如9张截屏),我们想删除前3张,勾选了前3张图标的CheckBox,结果第7、8、9张截屏的CheckBox也被勾选了,这当然不是我们希望的。
解决方法的思路:用一个map来保存每一行选中的状态;我们声明一个HashMap<Integer, View>来保存每一行数据 ,除第一行数据外,其他每行数据都通过getTag()得到已经渲染好的view来重复渲染剩余行的数据。
解决方法的思路:用一个map来保存每一行选中的状态;我们声明一个HashMap<Integer, View>来保存每一行数据 ,除第一行数据外,其他每行数据都通过getTag()得到已经渲染好的view来重复渲染剩余行的数据。
首先,我们来看一下关键代码:(具体代码实现,可以下载查看我的Github项目:
https://github.com/jscly/signal-detection)
//通过声明View,表示每一行数据都是一个view
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder = null;
//待查看图片的路径
final String currentImgFilePath = dirNameToSaveImg + "/" + imgList.get(position);
if (map.get(position) == null) {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = mInflater.inflate(R.layout.custom_listview_item, null);
holder = new ViewHolder();
holder.cbIsSelected = (CheckBox) view.findViewById(R.id.list_cbSelected);
holder.ivImg = (ImageView) view.findViewById(R.id.list_ivImg);
holder.tvImgName = (TextView) view.findViewById(R.id.list_tvImgName);
holder.tvPrtScTime = (TextView) view.findViewById(R.id.list_tvPrtScTime);
holder.ivNext = (ImageView) view.findViewById(R.id.list_ivNext);
map.put(position, view);
view.setTag(holder);
} else {
view = map.get(position);
holder = (ViewHolder) view.getTag();
}
holder.cbIsSelected.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
//保存当前CheckBox的选中状态
currentFileIsCheckedMap.put(currentImgFilePath, cb.isChecked());
if (cb.isChecked()) {
cb.setFocusable(true);
selectedImgList.add(currentImgFilePath);
//待删除文件名及其ItemInfo
filePath_currentItemInfoMap.put(currentImgFilePath,listItemInfo.get(position));
}
else {
cb.setFocusable(true);
selectedImgList.remove(currentImgFilePath);
filePath_currentItemInfoMap.remove(currentImgFilePath);
}
}
});
holder.ivNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((ImageView)v).setFocusable(true);
openPrtSc(currentImgFilePath);
}
});
holder.cbIsSelected.setChecked(currentFileIsCheckedMap.get(currentImgFilePath) != null ? currentFileIsCheckedMap.get(currentImgFilePath) : false);
holder.ivImg.setImageBitmap(listItemInfo.get(position).getImgBitmap());
holder.tvImgName.setText(listItemInfo.get(position).getImgName());
holder.tvPrtScTime.setText(sdf.format(
new Date(
listItemInfo.get(position).getPrtScTime()
)
).toString());
holder.ivNext.setImageResource(listItemInfo.get(position).getImgNextId());
return view;
}