支持多项选择的ExpandableListView

本文实例为大家分享了ExpandableListView多项选择展示的具体代码,供大家参考,具体内容如下

目标(需求):

1. 创建一个可展开可收缩的列表;

2. 其列表项包含多个checkable的部件,当选择某一行时,该行包含的checkable的部件需要作出相应的变化;

3. 可以选择多个列表项,并且这些列表项可被读出

结果图:

实现:

1. 创建主layout用于规划列表显示。对于具体的列表项,为了实现的方便我们也创建一个layout文件。

<?xml version="1.0" encoding="utf-8"?>
<com.home.mymultichecklistview.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="horizontal" >
 <com.home.mymultichecklistview.CheckableTextView
   android:id="@+id/item"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_marginTop="6dip"
   style="@style/text"
   android:layout_weight="1"
 /> 

 <com.home.mymultichecklistview.InertCheckBox
   android:id="@+id/checkbox"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_marginRight="5dp"
   android:maxWidth="40dp"
   android:maxHeight="40dp"
   android:focusable="false"
   android:layout_gravity="right"
   android:button="@drawable/checkbox"
 />  

</com.home.mymultichecklistview.CheckableLinearLayout>

2. 类似ListView,ExpandableListView也是通过Adapter来管理其包含的各种元素和操作,这里我们创建一个扩展自BaseExpandableListAdapter的Adapter。与ListView不同的是,ExpandableListAdapter要渲染实现两级View(Group级和列表项级)的操作。它通过getGroupView()渲染Group项,通过getChildView()渲染列表子项。

@Override
  public View getGroupView(int groupPosition, boolean isExpanded,
      View convertView, ViewGroup parent) {
    View groupView = convertView;
    if (groupView == null) {
      groupView = new TextView(context);
      ((TextView)groupView).setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
      groupView.setPadding(50,0,0,0);
    }
    ((TextView)groupView).setText(groupData[groupPosition]);
    ((TextView)groupView).setTextColor(context.getResources().getColor(R.color.fgcolor)); 

    return groupView;
  } 

  @Override
  public View getChildView(final int groupPosition, final int childPosition,
      boolean isLastChild, View convertView, ViewGroup parent) {
    View itemView = convertView;
    final ViewHolder vh;
    if (itemView == null) {
      LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      itemView = inflater.inflate(R.layout.item_view, null); 

      vh = new ViewHolder();
      vh.layout = (CheckableLinearLayout)itemView.findViewById(R.id.layout);
      vh.item = (TextView)itemView.findViewById(R.id.item);
      itemView.setTag(vh);
    } else {
      vh = (ViewHolder)itemView.getTag();
    }
    vh.item.setText(itemData[groupPosition][childPosition]);
    final ExpandableListView listView = ((ExpandableListView)((MainActivity)context).findViewById(R.id.list));
    final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
    listView.setItemChecked(position, checkedState[groupPosition][childPosition]);
    vh.layout.setOnClickListener(new OnClickListener() { 

      @Override
      public void onClick(View v) {
        ((CheckableLinearLayout)v).toggle();
        checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];
        listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
      }
    });
    return itemView;
  }

3. 为每一列表子项容器创建OnClickListener监听鼠标的点击事件。在这里要注意,由于列表子项包含了CheckBox,所以为了使点击事件不要被CheckBox捕获,我们需要创建一个扩展自CheckBox的类来屏蔽鼠标和键盘事件。同时,需要在这个容器里搜索其包含的checkable的部件并将check操作传给这些部件。

Adapter中的方法getChildView()需要实现鼠标点击监听器:

public View getChildView(final int groupPosition, final int childPosition,
      boolean isLastChild, View convertView, ViewGroup parent) {
  View itemView = convertView;
  final ViewHolder vh;
... 

    final int position = listView.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
    listView.setItemChecked(position, checkedState[groupPosition][childPosition]);
  vh.layout.setOnClickListener(new OnClickListener() { 

  @Override
  public void onClick(View v) {
    ((CheckableLinearLayout)v).toggle();
    checkedState[groupPosition][childPosition] = !checkedState[groupPosition][childPosition];
     listView.setItemChecked(position, ((CheckableLinearLayout)v).isChecked());
  }
 });
 return itemView;
} 

扩展自CheckBox的InertCheckBox需要屏蔽键盘和鼠标事件

public class InertCheckBox extends CheckBox {
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
  //直接返回false
  return false;
  } 

  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) {
  //直接返回false
  return false;
} 

  @Override
  public boolean onTouchEvent(MotionEvent event) {
  //直接返回false
  return false;
  } 

   @Override
   public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
  //直接返回false
  return false;
  ...
} 

列表项容器需要实现Checkable接口并且把check操作传递给其checkable的子部件

public class CheckableLinearLayout extends LinearLayout implements Checkable {
...
  @Override
  public void setChecked(boolean checked) {
  this.isChecked = checked;
  for (Checkable view : checkableViews) {
   view.setChecked(checked);
   }
  } 

  @Override
  public boolean isChecked() {
   return this.isChecked;
  } 

  @Override
  public void toggle() {
   isChecked = !isChecked;
   for (Checkable view : checkableViews)    {
  view.toggle();
   }
  } 

  @Override
  protected void onFinishInflate() {
  super.onFinishInflate(); 

    for (int i=0; i<this.getChildCount(); i++) {
  findCheckableChild(this.getChildAt(i));
  }
 } 

  private void findCheckableChild(View child) {
  if (child instanceof Checkable) {
    checkableViews.add((Checkable)child);
  } 

  if (child instanceof ViewGroup) {
      for (int i=0; i<((ViewGroup)child).getChildCount(); i++) {
    findCheckableChild(((ViewGroup) child).getChildAt(i));
    }
  }
  }
...
}

开发中遇到的问题:

1. 渲染后的child view类似于放在一个cache中,下一次再通过convertView取时,由于Group的收缩或扩展操作会隐藏/显示一些child view,导致某一child View的flat position发生变化,获取到的convertView不是原来希望获取的view。所以,每次获取到view后都需要对其内容重新设置(比如设置正确文本,设置监听器等)

2. check的状态设置很tricky。我开始认为直接在监听器中调用容器的toggle()方法即可。结果发现一旦某个group做了expand或collapse操作后,所有列表项的check状态全没了。后来发现原来group做了expand/collapse操作后,ListView会对其所有子项重新设置check状态,而check状态的值是存在ListView的一个SparseBooleanArray表里(mCheckStates)。由于没有对这个表进行设置,所以一刷新check状态就全丢了。并且由于这个表的key是基于拉平后所有可见的列表项的位置定的,当group扩展或收缩后,同一个列表项,它拉平后的位置还会变化。所以,为了解决这个问题,我在adapter里增加了一个二维表用于记录每一列表项的check状态。在执行 listView的setItemChecked函数时,其check状态是从这个自己创建的表中读出的,不能通过ListView的mCheckStates来读。这个我认为是ExpandableListView的一个缺陷。

遗留的已知问题:

我使用了@drawable/checkbox 来定义checkbox check 和uncheck时的图片,但当checkbox被check上时,这个checked的图片没有生效。不知道为什么,还需要进一步debug.

源程序:Multi-check-in-expandablelistview

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android ExpandableListView单选以及多选实现代码

    一.概述 ExpandableListView是常用的一个控件,今天自己做了个小练习,主要需求是单选以及多选的实现,看似比较简单,但是还是比较复杂,把代码贴给大家,有这种需求的可以参考一下. 二.效果截图 三.实现过程 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.

  • Android listview ExpandableListView实现多选,单选,全选,edittext实现批量输入的实例代码

    最近在项目开发中,由于项目的需求要实现一些列表的单选,多选,全选,批量输入之类的功能,其实功能的实现倒不是很复杂,需求中也没有涉及到复杂的动画什么之类,主要是解决列表数据复用的问题,解决好这个就可以了.下面是最近项目中涉及到的一些: listview实现多选.全选.取消全选: 下面是适配器,一开始在适配器的构造函数中,对数据进行初始化,同时定义一个集合用于管理listview的点击: class BatchAdpter extends BaseAdapter { private HashMap<

  • 支持多项选择的ExpandableListView

    本文实例为大家分享了ExpandableListView多项选择展示的具体代码,供大家参考,具体内容如下 目标(需求): 1. 创建一个可展开可收缩的列表: 2. 其列表项包含多个checkable的部件,当选择某一行时,该行包含的checkable的部件需要作出相应的变化: 3. 可以选择多个列表项,并且这些列表项可被读出 结果图: 实现: 1. 创建主layout用于规划列表显示.对于具体的列表项,为了实现的方便我们也创建一个layout文件. <?xml version="1.0&q

  • Android 中CheckBox多项选择当前的position信息提交的示例代码

    先给大家展示下效果图: 废话不多说了,下面通过示例代码给大家介绍checkbox 多项选择当前的position信息提交,具体代码如下所示: package com.dplustours.b2c.View.activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import andro

  • 易语言多项选择用法及实例讲解

    最近发现个好玩的易语言命令啊...相当于几个如果真 就是多项选择这个命令...看下多项选择的说明 调用格式:〈通用型〉 多项选择 (整数型 索引值,通用型 待选择项数据,... ) - 系统核心支持库->其他 英文名称:choose 从参数列表项目中选择并返回一个值.本命令为初级命令.命令参数表中最后一个参数可以被重复添加. 参数<1>的名称为"索引值",类型为"整数型(int)".命令会根据本索引值来返回选择项列表中的某个值.如果索引值是 1,则

  • Android实现单项、多项选择操作

    本文实例为大家分享了Android实现单项.多项选择操作的相关代码,供大家参考,具体内容如下 1.单项选择 1.1.布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.co

  • PHP与javascript对多项选择的处理

    我们经常要给用户作出多项选择进行处理,例如允许用户对列表项选择多项后删除选定项等.今天举个例子说明PHP和JavaScript分别是怎样处理多项选择的.今天我们做的是一个投票系统,对MySQL数据库itemtable表里的项目进行投票,且每个别IP能且只能投两票. 表itemtable是通过以下MySQL语句建立的: CREATE TABLE `itemtable` (`id` TINYINT( 4 ) NOT NULL AUTO_INCREMENT,`name` VARCHAR( 50 ) N

  • 微信小程序使用checkbox显示多项选择框功能【附源码下载】

    本文实例讲述了微信小程序使用checkbox显示多项选择框功能.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 ① index.wxml <checkbox-group bindchange="checkboxgroupBindchange"> <checkbox value="checkbox1">checkbox1</checkbox> <checkbox value="checkbox2&quo

  • Flutter 底部弹窗如何实现多项选择

    多选和单选的不同之处 单选的时候,选中一个就可以直接把结果返回,因此本身底部弹窗无需状态管理.但到多选的时候,需要知道当前选中的选项,有选项被点击的时候需要存储下来,当再次被点击的时候要清空这个选项,同时界面还需要同步更新,因此就涉及到状态管理了. 实现方式 在Flutter 中提供了一个 StatefulBuilder 的类,提供了一个 builder方法构建有状态组件,并且提供了状态更新方法,因此在里面完成状态管理. StatefulBuilder(builder: (context1, s

  • Flutter多项选择弹窗实现详解

    目录 多选和单选的不同之处 实现方式 界面变更 代码实现 总结 在Flutter 底部弹窗详解一篇中介绍了底部弹窗的实现.发出后有在琢磨如何实现多选,这也是很常用的一个功能.本篇介绍实现多选的思路和实现方式. 多选和单选的不同之处 单选的时候,选中一个就可以直接把结果返回,因此本身底部弹窗无需状态管理.但到多选的时候,需要知道当前选中的选项,有选项被点击的时候需要存储下来,当再次被点击的时候要清空这个选项,同时界面还需要同步更新,因此就涉及到状态管理了. 实现方式 在Flutter 中提供了一个

  • javascript实现的仿51job地址多项选择方式效果

    类似51job效果的地址选择 您已选择的城市汇总 请选择城市 [取消] [确定] 第0层 第1层 第2层 第3层 北京 福建 四川 江苏 上海 云南 贵州 黑龙江 吉林 辽宁 美国 阿富汗 日本 您已选择的城市 /* ------使用说明----- */ /* 添加城市方法: 添加组:找到id 是 "selectSub"中select标签下,添加option标签 value属性递增,找到 id 是 "selectSub",按照原有格式添加div,其id属性递增 添加

  • Android编程开发中ListView的常见用法分析

    本文实例讲述了Android编程开发中ListView的常见用法.分享给大家供大家参考,具体如下: 一.ListView的使用步骤 ListView的使用通常有以下三个要素: (1)ListView中每个条目的布局; (2)填充进入ListView中的内容; (3)将内容与页面进行整合的Adapter. 因此,使用ListView也通常有以下三个步骤: (1)创建ListView条目的布局文件(或使用Android SDK提供的布局); (2)创建填充进入ListView中的内容,如字符串.图片

随机推荐