这篇其实应该是属于写自定义单选或多选的ListView的基础教程,无奈目前许多人对此的实现大多都绕了远路,反而使得这正规的写法倒显得有些技巧性了。

本文原创,转载请注明在CSDN上的出处:

http://blog.csdn.net/maosidiaoxian/article/details/45867927

Android中,ListView可以设置choiceMode,可见Android对ListView的单选或多选是有进行封装的,然而我看到的许多单选或多选的ListView,包括我以前写的例子,以前几个老外封装的库,都是自己维护了一个集合,用于存放每个item的选中状态。这样一来,不但代码显得繁复,逻辑上也成冗余,而且容易出BUG。

其实,ListView中,已经自己维护了一个SparseBooleanArray,用于保存每一项的选中状态。而对于每一项,它是通过adapter的getView中获取的view,来设置它的选中状态的。所以,我们需要使得adapter中,getView中返回的这个view实现Checkable接口。下面,将介绍具体实现。

这里介绍的实现方式有两个,一种是从零写一个单选的ListView。另一种是调用我的一个库的代码来实现。因为我已经对相关的必要逻辑都封装在了两个类里,使得易于使用。

原生实现

1,先写item的布局文件。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="wrap_content">
    <RadioButton
        android:id="@+id/checkedView"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:layout_width="wrap_content"
        android:layout_height="48dp" />
    <TextView
        android:id="@+id/text"
        android:gravity="center_vertical"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="48dp" />

</RelativeLayout>

注意,这里的RadioButton,需要设置三个属性,分别是:

        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"

2,接下来,继承某个Layout,来实现可以单选的这个item。

package com.githang.android.choicelistview;

import android.content.Context;
import android.view.View;
import android.widget.Checkable;
import android.widget.FrameLayout;
import android.widget.RadioButton;
import android.widget.TextView;

/**
 * FIXME
 *
 * @author Geek_Soledad (msdx.android@qq.com)
 */
public class ChoiceView extends FrameLayout implements Checkable{

    private TextView mTextView;
    private RadioButton mRadioButton;

    public ChoiceView(Context context) {
        super(context);
        View.inflate(context, R.layout.item_single_choice, this);
        mTextView = (TextView) findViewById(R.id.text);
        mRadioButton = (RadioButton) findViewById(R.id.checkedView);
    }

    public void setText(String text) {
        mTextView.setText(text);
    }

    @Override
    public void setChecked(boolean checked) {
        mRadioButton.setChecked(checked);
    }

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

    @Override
    public void toggle() {
        mRadioButton.toggle();
    }
}

最后,在listview的adapter的getView方法里,返回这个实现了Checkable接口的ChoiceView。

package com.githang.android.choicelistview;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        List<String> data = new ArrayList<>();
        for(int i = 0; i < 5; i++) {
            data.add("test" + i);
        }
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        ListAdapter adapter = new ArrayAdapter<String>(this, R.layout.item_single_choice, data) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                final ChoiceView view;
                if(convertView == null) {
                    view = new ChoiceView(MainActivity.this);
                } else {
                    view = (ChoiceView)convertView;
                }
                view.setText(getItem(position));
                return view;
            }
        };
        listView.setAdapter(adapter);
    }

}

代码很简单方便,完全不用自己去维护一个选中状态的集合。Demo 项目下载地址:http://www.400gb.com/file/94898213


使用AndroidSnippet里的类实现

接下来还有更简单的实现方法,即使用我封装的类来实现。这种情况下,只需要写一个item的布局文件,然后写一个adapter即可,和写普通的ListView没多大区别。
item 的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="wrap_content">
    <RadioButton
        android:id="@+id/checkedView"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:layout_width="wrap_content"
        android:layout_height="48dp" />
    <TextView
        android:id="@+id/text"
        android:gravity="center_vertical"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="48dp" />

</RelativeLayout>

关于RadioButton的三个属性我已经在代码里封装好了,所以这里写不写那三个属性都无所谓。

接下来,就是使用我封装的ChoiceListAdapter,来实现单选(或多选)的ListView,代码如下:
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        ChoiceListAdapter adapter = new ChoiceListAdapter<String>(this, R.layout.item_single_choice,
                data, R.id.checkedView) {
            @Override
            protected void holdView(ChoiceLayout view) {
                view.hold(R.id.text);
            }

            @Override
            protected void bindData(ChoiceLayout view, int position, String data) {
                TextView text = view.get(R.id.text);
                text.setText(data);
            }
        };
        listView.setAdapter(adapter);

这里的ChoiceLayout 我还对holder进行了封装,用起来是不是更简洁方便?


关于AndroidSnippet 库,我已把代码托管到github :https://github.com/msdx/AndroidSnippet。其中关于单选列表的例子,在app module中有。

最后附上实现效果。
效果GIF图:


Android开发技巧——自定义单选或多选的ListView的更多相关文章

  1. Android开发技巧——使用PopupWindow实现弹出菜单

    在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用. 因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在 ...

  2. Android开发技巧——实现可复用的ActionSheet菜单

    在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: h ...

  3. Android开发技巧——自定义控件之增加状态

    Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...

  4. Android开发技巧——自定义控件之使用style

    Android开发技巧--自定义控件之使用style 回顾 在上一篇<Android开发技巧--自定义控件之自定义属性>中,我讲到了如何定义属性以及在自定义控件中获取这些属性的值,也提到了 ...

  5. Android开发技巧——自定义控件之自定义属性

    Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...

  6. Android开发技巧——自定义控件之组合控件

    Android开发技巧--自定义控件之组合控件 我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等. 还是那句老话,尽 ...

  7. Android开发技巧——写一个StepView

    在我们的应用开发中,有些业务流程会涉及到多个步骤,或者是多个状态的转化,因此,会需要有相关的设计来展示该业务流程.比如<停车王>应用里的添加车牌的步骤. 通常,我们会把这类控件称为&quo ...

  8. android开发之自定义组件

    android开发之自定义组件 一:自定义组件: 我认为,自定义组件就是android给我们提供的的一个空白的可以编辑的图片,它帮助我们实现的我们想要的界面,也就是通过自定义组件我们可以把我们要登入的 ...

  9. 50个android开发技巧

    50个android开发技巧 http://blog.csdn.net/column/details/androidhacks.html

随机推荐

  1. Hadoop学习笔记1:伪分布式环境搭建

    在搭建Hadoop环境之前,请先阅读如下博文,把搭建Hadoop环境之前的准备工作做好,博文如下: 1.CentOS 6.7下安装JDK , 地址: http://blog.csdn.net/yule ...

  2. 详解EBS接口开发之采购订单导入

    采购订单常用标准表简介 1.1   常用标准表 如下表中列出了与采购订单导入相关的表和说明: 表名 说明 其他信息 po.po_headers_all 采购订单头 采购订单号,采购类型,供应商,地点, ...

  3. Android开发基础规范(二)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52614696 前言:Androi ...

  4. 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。

    有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列.对于1<=i,j<=k,求k个最小的(ai+bj).要求算法尽量高效. int * ...

  5. iOS让软键盘消失的简单方法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 一些文本输入控件等待输入时会弹出软键盘,我们可以设置这些控件的 ...

  6. J2EE进阶(四)Spring配置文件详解

    J2EE进阶(四)Spring配置文件详解 前言 Spring配置文件是用于指导Spring工厂进行Bean生产.依赖关系注入(装配)及Bean实例分发的"图纸".Java EE程 ...

  7. tomcat如何路由映射网址

    对于web容器来说,根据请求客户端路径路由到对应的资源属于其核心功能,假设用户在自己电脑上使用浏览器输入网址http://www.test.com/test/index.jsp,报文通过互联网网络到达 ...

  8. Linux 基于IPC机制实现进程间的共享内存处理

    今天学习了相关于IPC(InterProcess Communication ,进程间通信)的相关知识.就做个笔记,一来让大家检查一下我的理解方面是不是有错误,二来也为了能让更多的博友们了解到相关的知 ...

  9. 精通CSS+DIV网页样式与布局--CSS段落效果

    在上一篇博文中,小编主要详细的介绍了CSS是如何控制文字的显示效果,随着需求的不断变更,那么我们如何对段落进行相关操作,以达到我们想要的效果呢,接下来,为了需要,小编继续来完善CSS对段落的控制的显示 ...

  10. Docker教程:docker的概念及安装

    http://blog.csdn.net/pipisorry/article/details/50754385 Why docker 对于运维来说,Docker提供了一种可移植的标准化部署过程,使得规 ...