Android开发技巧——自定义单选或多选的ListView

简介: 这篇其实应该是属于写自定义单选或多选的ListView的基础教程,无奈目前许多人对此的实现大多都绕了远路,反而使得这正规的写法倒显得有些技巧性了。 本文原创,转载请注明在CSDN上的出处: http://blog.csdn.net/maosidiaoxian/article/details/45867927 Android中,ListView可以设置choiceMode,可见Android对ListView的单选或多选是有进行封装的,然而我看到的许多单选或多选的ListView,包括我以前写的例子,以前几个老外封装的库,都是自己维护了一个集合,用于存放每个item的选中状态。

这篇其实应该是属于写自定义单选或多选的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图:


目录
相关文章
|
8月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1561 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1075 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1153 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
9月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
902 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
8月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
404 0
|
9月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
1269 6
|
11月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
475 0
|
XML Java Android开发
如何美化android程序:自定义ListView背景
如何美化android程序:自定义ListView背景
281 2
|
Android开发
Android自定义ListView和GridView解决滑动冲突和显示不全
Android自定义ListView和GridView解决滑动冲突和显示不全
321 0
|
Android开发
Android项目实战(十五):自定义不可滑动的ListView和GridView
原文:Android项目实战(十五):自定义不可滑动的ListView和GridView 不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView { public NoScrollLi...
1186 0