题外话:

在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. 基于docker+reveal.js搭建一个属于自己的在线ppt网站

    前言 最近热衷于Docker,由于这段时间使用Docker来折腾自己的服务器,越来越感觉这是一种及其被应该推广的技术,因此想在公司内部也做一次技术分享.当然,如果只是做的PPT,我就不写这文章了.既然 ...

  2. android 开源收藏

    第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...

  3. display:box和display:flex填坑之路

    背景分析:最近做移动端项目时,遇到一个常见的需求: 可以滑动的导航,如下图 虽然是很常见的一个布局,但在移动端没有做过,想当然的写下以下的样式,简单描述下: 父元素 width:100%: overf ...

  4. deepin 环境变量配置加载顺序

    加载顺序,默认是没有 .bash_profile 文件 1. non-login 方式 ~$ su deepin run /ect/bash.bashrc run .bashrc 2.login 方式 ...

  5. Cracking the Coding Interview 题目分析笔记—— Array and String

    1.Determine if a string has all unique characters learn: 为了减少空间利用率,其比较优秀的算法一般都适用位操作 返回值的命名方法,我们需要学习 ...

  6. Android开发之漫漫长途 番外篇——自定义View的各种姿势2

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  7. Webstorm 快捷键大全 整理收录

    "工欲善其事,必先利其器" 作为一名开发人员,好用的工具能让你效率更高,剩下的时间用来偷懒吹牛逼吧... 以下整理Webstorm快捷键大全   Windows版本 注释(// 或 ...

  8. Ubuntu 17.04 安装

    不忘初心,方得始终. 今天听别人说17.04发布了,我是开心的不得了,赶紧下载了一个,准备安装在自己的本子上.这段时间已经花费了更多的时间在docker和OpenStack上面,没时间看新闻了,因此今 ...

  9. 如果nginx启动失败,错误解决

    解决上面问题: /usr/sbin/groupadd -f www /usr/sbin/useradd -g www www 这方法常见出现时反向代理时,ssl的授权用户不存在的情况下出现的:.

  10. 音频传输之Jitter Buffer设计与实现

    在语音通信中Jitter Buffer(下面简称JB)是接收侧一个非常重要的模块,它是决定音质的重要因素之一.一方面它会把收到的乱序的语音包排好序放在buffer里正确的位置上,另一方面它把接收到的语 ...