欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-05 14:22:27
首先来说一下具体的需求是什么样的: 需求如图所示,这里面有abcd四个选项的题目,当点击a选项,如果a是正确的答案,则变成对勾的图案,如果是错误答案,则变成错误的图案...

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

探究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<convertmodel> list; 
private context mcontext; 
public convertviewadapter(context context, list<convertmodel> 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; 
} 
}

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

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

是的,由于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<convertmodel> list; 
private context mcontext; 
public convertviewadapter(context context, list<convertmodel> 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); 
<span style="color:#cc0000;">if (textutils.isempty(module.check)) { 
clearselectstate(mviewholder); 
} else { 
judgeselect(mviewholder, getchecktextview(mviewholder, module.check), module.check, module.rightoption, position); 
}</span> 
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) { 
<span style="color:#cc0000;">module.check = "a";</span> 
judgeselect(mviewholder, mviewholder.tvselecta, "a", select, position); 
} 
}); 
mviewholder.tvselectb.setonclicklistener(new view.onclicklistener() { 
@override 
public void onclick(view v) { 
<span style="color:#cc0000;">module.check = "b";</span> 
judgeselect(mviewholder, mviewholder.tvselectb, "b", select, position); 
} 
}); 
mviewholder.tvselectc.setonclicklistener(new view.onclicklistener() { 
@override 
public void onclick(view v) { 
<span style="color:#cc0000;">module.check = "c"; 
</span> judgeselect(mviewholder, mviewholder.tvselectc, "c", select, position); 
} 
}); 
mviewholder.tvselectd.setonclicklistener(new view.onclicklistener() { 
@override 
public void onclick(view v) { 
<span style="color:#cc0000;">module.check = "d";</span> 
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; 
} 
<span style="color:#cc0000;">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; 
}</span> 
class viewholder { 
textview tvtitle; 
textview tvselecta; 
textview tvselectb; 
textview tvselectc; 
textview tvselectd; 
} 
}

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

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

总结:

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

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

以上所述是小编给大家介绍的探究android中listview复用导致布局错乱的解决方案,希望对大家有所帮助