热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

探究Android中ListView复用导致布局错乱的解决方案

这篇文章主要介绍了探究Android中ListView复用导致布局错乱的解决方案,非常不错,具有参考借鉴价值,需要的朋友可以参考下

首先来说一下具体的需求是什么样的:

需求如图所示,这里面有ABCD四个选项的题目,当点击A选项,如果A是正确的答案,则变成对勾的图案,如果是错误答案,则变成错误的图案,这里当时在写的时候觉得很简单,只要是在点击的时候判断我点击的选项与正确答案是否一样,是一样就将图片换成正确的样式,如果不一样就换成错误的样式,于是我便写了下面的代码(只贴出了核心Adapter中的代码)

package com.fizzer.anbangproject_dahuo_test.Adapter; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.graphics.drawable.Drawable; 
import android.os.Build; 
import android.text.TextUtils; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.TextView; 
import com.fizzer.anbangproject_dahuo_test.Model.ConvertModel; 
import com.fizzer.anbangproject_dahuo_test.R; 
import java.util.List; 
/** 
* Created by Fizzer on 2016/10/8. 
* Email: doraemonmqq@sina.com 
*/ 
public class ConvertViewAdapter extends BaseAdapter { 
private List list; 
private Context mContext; 
public ConvertViewAdapter(Context context, List list) { 
mCOntext= context; 
this.list = list; 
} 
@Override 
public int getCount() { 
if (list == null) { 
return 0; 
} else { 
return list.size(); 
} 
} 
@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
ViewHolder mViewHolder; 
if (cOnvertView== null) { 
cOnvertView= View.inflate(mContext, R.layout.view_upgradepartnet_topic_layout, null); 
mViewHolder = new ViewHolder(); 
mViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle); 
mViewHolder.tvSelectA = (TextView) convertView.findViewById(R.id.tvSelectA); 
mViewHolder.tvSelectB = (TextView) convertView.findViewById(R.id.tvSelectB); 
mViewHolder.tvSelectC = (TextView) convertView.findViewById(R.id.tvSelectC); 
mViewHolder.tvSelectD = (TextView) convertView.findViewById(R.id.tvSelectD); 
convertView.setTag(mViewHolder); 
} else { 
mViewHolder = (ViewHolder) convertView.getTag(); 
} 
ConvertModel module = list.get(position); 
mViewHolder.tvTitle.setText("Q" + (position + 1) + ":" + module.title); 
mViewHolder.tvSelectA.setText(module.optionA); 
mViewHolder.tvSelectB.setText(module.optionB); 
mViewHolder.tvSelectC.setText(module.optionC); 
mViewHolder.tvSelectD.setText(module.optionD); 
initListener(mViewHolder, module.rightOption, position, module); 
return convertView; 
} 
@Override 
public Object getItem(int position) { 
return null; 
} 
@Override 
public long getItemId(int position) { 
return 0; 
} 
private void initListener(final ViewHolder mViewHolder, final String select, final int position, final ConvertModel module) { 
mViewHolder.tvSelectA.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
judgeSelect(mViewHolder, mViewHolder.tvSelectA, "A", select, position); 
} 
}); 
mViewHolder.tvSelectB.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
judgeSelect(mViewHolder, mViewHolder.tvSelectB, "B", select, position); 
} 
}); 
mViewHolder.tvSelectC.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
judgeSelect(mViewHolder, mViewHolder.tvSelectC, "C", select, position); 
} 
}); 
mViewHolder.tvSelectD.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
judgeSelect(mViewHolder, mViewHolder.tvSelectD, "D", select, position); 
} 
}); 
} 
private void clearSelectState(ViewHolder mViewHolder) { 
mViewHolder.tvSelectA.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_a), null, null, null); 
mViewHolder.tvSelectB.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_b), null, null, null); 
mViewHolder.tvSelectC.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_c), null, null, null); 
mViewHolder.tvSelectD.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_d), null, null, null); 
} 
private void judgeSelect(ViewHolder viewHolder, TextView text, String select, String rightSelect, int position) { 
//清楚之前的状态 
clearSelectState(viewHolder); 
if (select.equals(rightSelect)) { 
text.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_right), null, null, null); 
} else { 
text.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_error), null, null, null); 
} 
} 
@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
private Drawable getDrawableResource(int res) { 
Drawable drawable = mContext.getDrawable(res); 
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight()); 
return drawable; 
} 
class ViewHolder { 
TextView tvTitle; 
TextView tvSelectA; 
TextView tvSelectB; 
TextView tvSelectC; 
TextView tvSelectD; 
} 
}

写完这段代码信心满满,觉得没问题了,但是在手机上一运行,发现出问题了,效果如下:

是的,由于listview的布局复用机制,导致下面没有选择的条目也因为复用而选择了选项

其实解决的方法很简单,就是将这个选中的条目与该条目对应的model相关联起来,具体怎么做呢,下面来仔细的分析分析,

首先在创建model的时候添加一个默认的字段,这个字段就是你选择的选项,当然初始值是没有的,在getView中对布局进行初始化的时候,就去判断这个字段是否有值,并且值为多少,如果有值,就去判断值为正确还是为错误,为正确则替换成正确的图片,如果为错误,则替换成错误的图片,如果没有值,则显示原始的ABCD四种初始化图片,这样,问题就迎刃而解了

下面贴出完整的代码,其实就跟上面的代码是差不多的,只不过在对model中添加的那个字段进行了一些复制与判断

package com.fizzer.anbangproject_dahuo_test.Adapter; 
import android.annotation.TargetApi; 
import android.content.Context; 
import android.graphics.drawable.Drawable; 
import android.os.Build; 
import android.text.TextUtils; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.TextView; 
import com.fizzer.anbangproject_dahuo_test.Model.ConvertModel; 
import com.fizzer.anbangproject_dahuo_test.R; 
import java.util.List; 
/** 
* Created by Fizzer on 2016/10/8. 
* Email: doraemonmqq@sina.com 
*/ 
public class ConvertViewAdapter extends BaseAdapter { 
private List list; 
private Context mContext; 
public ConvertViewAdapter(Context context, List list) { 
mCOntext= context; 
this.list = list; 
} 
@Override 
public int getCount() { 
if (list == null) { 
return 0; 
} else { 
return list.size(); 
} 
} 
@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
ViewHolder mViewHolder; 
if (cOnvertView== null) { 
cOnvertView= View.inflate(mContext, R.layout.view_upgradepartnet_topic_layout, null); 
mViewHolder = new ViewHolder(); 
mViewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle); 
mViewHolder.tvSelectA = (TextView) convertView.findViewById(R.id.tvSelectA); 
mViewHolder.tvSelectB = (TextView) convertView.findViewById(R.id.tvSelectB); 
mViewHolder.tvSelectC = (TextView) convertView.findViewById(R.id.tvSelectC); 
mViewHolder.tvSelectD = (TextView) convertView.findViewById(R.id.tvSelectD); 
convertView.setTag(mViewHolder); 
} else { 
mViewHolder = (ViewHolder) convertView.getTag(); 
} 
ConvertModel module = list.get(position); 
mViewHolder.tvTitle.setText("Q" + (position + 1) + ":" + module.title); 
mViewHolder.tvSelectA.setText(module.optionA); 
mViewHolder.tvSelectB.setText(module.optionB); 
mViewHolder.tvSelectC.setText(module.optionC); 
mViewHolder.tvSelectD.setText(module.optionD); 
initListener(mViewHolder, module.rightOption, position, module); 
if (TextUtils.isEmpty(module.check)) { 
clearSelectState(mViewHolder); 
} else { 
judgeSelect(mViewHolder, getCheckTextView(mViewHolder, module.check), module.check, module.rightOption, position); 
} 
return convertView; 
} 
@Override 
public Object getItem(int position) { 
return null; 
} 
@Override 
public long getItemId(int position) { 
return 0; 
} 
private void initListener(final ViewHolder mViewHolder, final String select, final int position, final ConvertModel module) { 
mViewHolder.tvSelectA.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
module.check = "A"; 
judgeSelect(mViewHolder, mViewHolder.tvSelectA, "A", select, position); 
} 
}); 
mViewHolder.tvSelectB.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
module.check = "B"; 
judgeSelect(mViewHolder, mViewHolder.tvSelectB, "B", select, position); 
} 
}); 
mViewHolder.tvSelectC.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
module.check = "C"; 
 judgeSelect(mViewHolder, mViewHolder.tvSelectC, "C", select, position); 
} 
}); 
mViewHolder.tvSelectD.setOnClickListener(new View.OnClickListener() { 
@Override 
public void onClick(View v) { 
module.check = "D"; 
judgeSelect(mViewHolder, mViewHolder.tvSelectD, "D", select, position); 
} 
}); 
} 
private void clearSelectState(ViewHolder mViewHolder) { 
mViewHolder.tvSelectA.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_a), null, null, null); 
mViewHolder.tvSelectB.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_b), null, null, null); 
mViewHolder.tvSelectC.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_c), null, null, null); 
mViewHolder.tvSelectD.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_d), null, null, null); 
} 
private void judgeSelect(ViewHolder viewHolder, TextView text, String select, String rightSelect, int position) { 
//清楚之前的状态 
clearSelectState(viewHolder); 
if (select.equals(rightSelect)) { 
text.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_right), null, null, null); 
} else { 
text.setCompoundDrawables(getDrawableResource(R.drawable.ic_select_error), null, null, null); 
} 
} 
@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
private Drawable getDrawableResource(int res) { 
Drawable drawable = mContext.getDrawable(res); 
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight()); 
return drawable; 
} 
private TextView getCheckTextView(ViewHolder mViewHolder, String rightSelect) { 
if ("A".equals(rightSelect)) { 
return mViewHolder.tvSelectA; 
} else if ("B".equals(rightSelect)) { 
return mViewHolder.tvSelectB; 
} else if ("C".equals(rightSelect)) { 
return mViewHolder.tvSelectC; 
} else if ("D".equals(rightSelect)) { 
return mViewHolder.tvSelectD; 
} 
return null; 
} 
class ViewHolder { 
TextView tvTitle; 
TextView tvSelectA; 
TextView tvSelectB; 
TextView tvSelectC; 
TextView tvSelectD; 
} 
}

其中标红的就是新添的代码,加上这些后,问题就解决了,来看一下解决后的代码运行情况:

总结:

最后来总结一下这个问题的解决思路吧:

首先就是需要在该填充器对应的实体类中添加一个选中的(check)字段,在进行getview操作中,去根据这个check字段来进行相应的操作,如过有值,则设置成对应的样式,如果没有值,则设置成没有值得样式,当然,在用户点击的时候,要及时的对该字段进行赋值,类似的,像Listview中有checkbox也可以采用同样的方法来进行解决。

以上所述是小编给大家介绍的探究Android中ListView复用导致布局错乱的解决方案,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
author-avatar
Colorful_Dong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有