题外话:

在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. params SqlParameter[] commandParameters(转)

    C#代码  ExecuteReader(string connectionString, CommandType commandType, string commandText, params Sql ...

  2. Linux 链接详解----静态链接实例分析

    由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...

  3. Jfinal启动原理及源码简析

    以下所有源码只截取了部分代码,标题即为类名 1.Web.xml <filter-name>jfinal</filter-name> <filter-class>co ...

  4. Elasticsearch中Head插件的使用

    在学习Elasticsearch的过程中,必不可少需要通过一些工具查看es的运行状态以及数据.如果都是通过rest请求,未免太过麻烦,而且也不够人性化.此时,head可以完美的帮助你快速学习和使用El ...

  5. HDU3790-最短路径问题

    最短路径问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  6. javassist:字节码编辑器工具

    简介: javassist是一款可以在运行时生成字节码的工具,可以通过它来构造一个新的class对象.method对象,这个class是运行时生成的.可以通过简短的几行代码就可以生成一个新的class ...

  7. solr6.5.0版本(Windows安装图解)

    此教程为solr6.5.0安装,自己制作,希望可以帮到你们.

  8. 【DevOps】团队敏捷开发系列--开山篇

    随着软件发布迭代的频率越来越高,传统的「瀑布型」(开发-测试-发布)模式已经不能满足快速交付的需求.2009 年左右 DevOps 应运而生,开发运维一体化,通过自动化工具与流程让整个软件开发构建.测 ...

  9. PHP中的会话控制

    了解HTTP(超文本传输协议)可以知道,它采用请求与响应的模式,最大的特点就是无连接无状态. 无连接:每次连接仅处理一个客户端的请求,得到服务器响应后,连接就结束了 无状态:每个请求都是独立的,服务器 ...

  10. Ajax 学习总结

    Ajax 技术在 JavaWeb 应用中随处可见,比如购物车中根据商品数量及时更新等应用,那么我们今天就来说说 Ajax 的一些小应用! Ajax 技术也就是允许浏览器与服务器通信而无需刷新当前页面, ...