题外话:

在xamarin android的开发中基本上所有人都会遇到这个小小的坎,的确有点麻烦,当时我也折腾了好一半天,如果你能看到这篇博客,说明你和我当初也是一样的焦灼,如果你想解决掉这个小小的坎,那么不要着急,一步一步来。我之前写过一篇Xamarin Android ListView简单的例子,例子入门级别的,Xamarin
Android ListView简单用法
,你也可以下载这个Demo ListView Demo下载结合下面的代码,那么你的问题马上就能解决。

Adapter中的GetView没有经过优化的代码:

为了使问题更直观,更便于理解,我们先来看看adapter中的重写方法GetView并没有经过优化的代码。我也看过网上很多博客,都是直接ListView优化后的代码来介绍解决这个问题,我觉得新手并不一定能够很懂易就能理解。
<pre name="code" class="csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using DeBug = System.Diagnostics.Debug;
namespace DrawerLayout.Adapter
{
public class News {
public int Pv { get; set; }
public string Title { get; set; }
public News(string title,int Pv)
{
this.Title = title;
this.Pv = Pv;
}
}
public class NewsAdapter : BaseAdapter
{
private List<News> data;
private Context context; public override int Count
{
get
{
return data.Count;
}
} public NewsAdapter(List<News> data,Context context)
{
this.data = data;
this.context = context;
}
public override Java.Lang.Object GetItem(int position)
{
return null;
} public override long GetItemId(int position)
{
return position;
}
private int count;
public override View GetView(int position, View convertView, ViewGroup parent)
{
convertView = LayoutInflater.From(context).Inflate(Resource.Layout.lv_test,parent,false);
TextView title = convertView.FindViewById<TextView>(Resource.Id.tv_title);
TextView pv = convertView.FindViewById<TextView>(Resource.Id.tv_pv);
CheckBox chk = convertView.FindViewById<CheckBox>(Resource.Id.chk_test);
pv.Text = data[position].Pv.ToString();
title.Text = data[position].Title;
DeBug.Write($"执行GetView第{position}次");//DeBug.Write直接在输出里面看到到底发生了什么
DeBug.Write(dictChk[position]);
return convertView;
}
}
}

Xamarin  android中ListView中的CheckBox在滑动的时候失去状态的根本原因:

遇到这个问题,我们首先要知道原因。我们就这个没有优化的代码很容易会发现每一次轻轻的滑动,都会触发GetView方法。滑动一个Item的距离就触发两次,依次类推。反正要知道的是滑动的时候会触发GetView方法就行了,在执行GetView方法,代码一目了然,重新实例化CheckBox,选中的状态并没有维持住。我们现在原因找到,解决的办法就简单多了。直接上代码,用一个Dictionary保存每一次单击Checkbox时状态,就ok,不会这么简单,就是这么简单,直接上代码了.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using DeBug = System.Diagnostics.Debug;
namespace DrawerLayout.Adapter
{
public class News {
public int Pv { get; set; }
public string Title { get; set; }
public News(string title,int Pv)
{
this.Title = title;
this.Pv = Pv;
}
}
public class NewsAdapter : BaseAdapter
{
private List<News> data;
private Context context;
private Dictionary<int, bool> dictChk = new Dictionary<int, bool>(); public override int Count
{
get
{
return data.Count;
}
} public NewsAdapter(List<News> data,Context context)
{
this.data = data;
this.context = context;
for (int i = 0; i < data.Count; i++)
{
dictChk.Add(i,false);
}
}
public override Java.Lang.Object GetItem(int position)
{
return null;
} public override long GetItemId(int position)
{
return position;
}
private int count;
public override View GetView(int position, View convertView, ViewGroup parent)
{
convertView = LayoutInflater.From(context).Inflate(Resource.Layout.lv_test,parent,false);
TextView title = convertView.FindViewById<TextView>(Resource.Id.tv_title);
TextView pv = convertView.FindViewById<TextView>(Resource.Id.tv_pv);
CheckBox chk = convertView.FindViewById<CheckBox>(Resource.Id.chk_test);
pv.Text = data[position].Pv.ToString();
title.Text = data[position].Title;
chk.Checked = dictChk[position];//每一个Checkbox是否选中是直接根据dicChk的key(position)获取是否选中
chk.CheckedChange += (s, e) =>
{
dictChk[position] = e.IsChecked;//每一次单击CheckBox,dictChk都会保存单击哪一个(position)的状态
};
DeBug.Write($"执行GetView第{position}次");//DeBug.Write直接在输出里面看到到底发生了什么
DeBug.Write(dictChk[position]);
return convertView;
}
}
}

效果图:


这样肯定不行啊!!一般ListView中的控件都会加一个类 ViewHolder来优化啊.

这样肯定不行的,的确这样肯定没有达到你想要的结果,那么经过ListView优化后的怎样来解决这个问题呢?好的,我们先来看一下,listview优化后的代码一般都会是这样的
        public override View GetView(int position, View convertView, ViewGroup parent)
{ ViewHolder holder = null;
if (convertView == null)
{
convertView = LayoutInflater.From(context).Inflate(Resource.Layout.lv_test, parent, false);
holder = new ViewHolder();
holder.tv_title = convertView.FindViewById<TextView>(Resource.Id.tv_title);
holder.tv_pv = convertView.FindViewById<TextView>(Resource.Id.tv_pv);
holder.chk_status = convertView.FindViewById<CheckBox>(Resource.Id.chk_test);
convertView.Tag = holder;
}
else {
holder = (ViewHolder)convertView.Tag;
}
holder.tv_pv.Text = data[position].Pv.ToString();
holder.tv_title.Text = data[position].Title;
DeBug.Write($"执行GetView第{position}次");
DeBug.Write(dictChk[position]);
return convertView;
}

以上代码所出现的问题是在listview滑动的时候,比如你手机能够看到6项, 选中第一项之后,滑动之后第七项就选中了,再次反复滑动第1,7项一直都是选中的状态那么原因出在哪里呢?调试的时候我们会很容易看到发生的清空。原因我引用别人博客的一段话,个人觉得解释还是蛮清楚的:

Getview()方法是baseadapter里面一个重要的方法,它是在android显示listview里面的内容的时候回调的一个方法。下面就讲讲这个方法的工作机制(个人观点,如有不对,望指出)现在假设我们有10项内容要显示,但是一屏只能显示5项,那么android会首先创建6项对应的item的view的实例并缓存起来,当滑动屏幕,第一项还未移除屏幕,然后第6项已经进入了屏幕的时候,就会把多余的那个view实例用来显示第6项的内容,只有在第7项已经进入屏幕,但是第1项还未移除屏幕的时候才会新建一个view来显示同时缓存起来,此后就将移除屏幕的view用来显示新进入屏幕的item。
        public override View GetView(int position, View convertView, ViewGroup parent)
        {             ViewHolder holder = null;
            News item = data[position];
            if (convertView == null)
            {
                convertView = LayoutInflater.From(context).Inflate(Resource.Layout.lv_test, parent, false);
                holder = new ViewHolder();
                holder.tv_title = convertView.FindViewById<TextView>(Resource.Id.tv_title);
                holder.tv_pv = convertView.FindViewById<TextView>(Resource.Id.tv_pv);
                holder.chk_status = convertView.FindViewById<CheckBox>(Resource.Id.chk_test);
                convertView.Tag = holder;
            }
            else
            {
                holder = (ViewHolder)convertView.Tag;
            }
            holder.chk_status.Tag = position;
            holder.tv_pv.Text = data[position].Pv.ToString();
            holder.tv_title.Text = data[position].Title;
<span style="color:#FF0000;">holder.chk_status.Checked = dictChk[(int)holder.chk_status.Tag];</span>
            holder.chk_status.CheckedChange += (s, e) =>
            {
                DeBug.Write((int)holder.chk_status.Tag);
<span style="color:#FF0000;">dictChk[(int)holder.chk_status.Tag] = e.IsChecked;</span>
            };
            DeBug.Write($"执行GetView第{position}次");
            DeBug.Write(dictChk[position]);
            return convertView;
        }

position参数的误区:

加上上面两行红色的代码就可以完全解决listView滑动时失去ChecxBox状态的bug了,刚开始学的时候不能理解这个bug是因为这个GetView中的position参数,当你刚学会用这个listview的时候你一定以为position不就是有多少条数据就多大吗?但是实际却是完全相反的,你手机能显示6条数据。position一直都是0-5,当你滑动到2-7的数据时,position还是0-5。还有CheckBox的状态也可以用用实体字段来保存.

Android中Tag是什么

既然不能position来做标识,那就用Tag。这样问题似乎简单多了,好像并没有想象中的复杂啊。简单点说,Tag的作用是和Id的作用是一样的,程序中调用对应的控件用(findViewById(R.tag.chk),findViewByTag(R.tag.chk))!不过和使用tag相比,使用Id进行查找!效率更快!但是在xamarin android中好像没有Tag这种查找控件的方式.

所以我们就要用Tag来保存这个每一个CheckBox的状态

  <span style="color:#FF0000;">holder.chk_status.Checked = dictChk[(int)holder.chk_status.Tag];</span>

看到这里是不是觉得很简单啊!!!!嘻嘻。

[置顶] android ListView包含Checkbox滑动时状态改变的更多相关文章

  1. android listview优化:滑动时颜色错乱问题

      最近android的listview写多了,也学习了各种listview的优化,列如viewHolder的使用.今天做item颜色设置时遇到一个新的问题.我这里设置“未完成”是灰色的,“已完成”是 ...

  2. android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法

    adapter+线程 1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了.但这样有的时候adapter的中 ...

  3. (转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题 标签: scrollviewandroid滑动嵌套 2015-07-16 17:24 1112 ...

  4. [置顶] Android开发百科全书

    友情提示根据目录 快速查找问题 %1$s %1$d Android string 1.整型,比如"我今年23岁了",这个23是整型的.在string.xml中可以这样写,<s ...

  5. [置顶] Android开发笔记(成长轨迹)

    分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...

  6. android listview 使用checkbox问题

    在android中使用listview时需要了解listview加载数据的原理,为了避免listview由于列表项过多每次需要进行new造成性能低下的问题,android中的listview使用了控件 ...

  7. Android ListView分页加载时图片显示问题

    场景:Android ListView需要分页加载,每个item中会有图片,图片又是从网络下载的. 问题:在滑动加载下一页时,上一页的图片明明已经下载完成了,但是无法显示出来. Bug重现: 1,加载 ...

  8. Android RecyclerView使用 及 滑动时加载图片优化方案

    1.控制线程数量 + 数据分页加载2.重写onScrollStateChanged方法 这个我们后面再谈,下面先来看看RecyclerView控件的使用及我们为什么选择使用它 RecyclerView ...

  9. Fresco对Listview等快速滑动时停止加载

    Fresco中在listview之类的快速滑动时停止加载,滑动停止后恢复加载: 1.设置图片请求是否开启 // 暂停图片请求 public static void imagePause() { Fre ...

随机推荐

  1. JDK8新特性一览

    转载自:http://blog.csdn.net/qiubabin/article/details/70256683 官方新特性说明地址 Jdk8新特性.png 下面对几个常用的特性做下重点说明. 一 ...

  2. 开源API测试工具 Hitchhiker v0.5更新 - 完善细节

    Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持上传脚本定制请求,可以轻松部署到本地,和你的team成员一起管理Ap ...

  3. 在没有DOM操作的日子里,我是怎么熬过来的(中)

    前言 继上篇推送之后,在掘金.segmentfault.简书.博客园等平台上迅速收到了不俗的反馈,大部分网友都留言说感同身受,还有不少网友追问中篇何时更新.于是,闰土顺应呼声,在这个凛冽的寒冬早晨,将 ...

  4. 【正则表达式】--python(表示字符)

    [前修知识] match :匹配    span:范围 match 是从头往后开始匹配,search不按照顺序,直接获取自己想要的,有就显示,没有就None r 代表反转义,前面也提到过这个知识,如果 ...

  5. Java第三季

    1.异常简介: (1) Java中的所有不正常类都继承于Throwable类.Throwable主要包括两个大类,一个是Error类,另一个是 Exception类: (2)其中Error类中包括虚拟 ...

  6. 如何编写gitignore文件

    原文链接:https://www.cnblogs.com/jingtyu/p/6831772.html 为什么要有.gitignore文件 项目中经常会生成一些Git系统不需要追踪(track)的文件 ...

  7. 教我徒弟Android开发入门(一)

    前言: 这个系列的教程是为我徒弟准备的,也适合还不懂java但是想学android开发的小白们~ 本系列是在Android Studio的环境下运行,默认大家的开发环境都是配置好了的 没有配置好的同学 ...

  8. Android崩溃提示 “EGL_BAD_CONFIG"

    这两天将之前提到的一个室内定位程序的ArcGIS的SDK从10.2.8迁移到100.1.0. 期间反复出现奇怪的问题,最终定位到这个问题: java.lang.RuntimeException: cr ...

  9. 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

    1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾 ...

  10. git以及github的初级入门(一)

    本身学习git的操作是没什么兴趣的,毕竟原本是win平台学的java开发,git下那么多复制的命令行操作确实比较让人头疼,直到昨天我打开计算机的时候,我放置项目的E盘,以及F盘,G盘盘符都不见了!!我 ...