android listview自定义顶部,Android开发技巧——自定义单选或多选的ListView

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

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"?>

android:layout_width="match_parent" android:layout_height="wrap_content">

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" />

android:id="@+id/text"

android:gravity="center_vertical"

android:layout_alignParentRight="true"

android:layout_width="wrap_content"

android:layout_height="48dp" />

注意,这里的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 ([email protected])

*/

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 data = new ArrayList<>();

for(int i = 0; i 

data.add("test" + i);

}

ListView listView = (ListView) findViewById(R.id.list_view);

listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

ListAdapter adapter = new ArrayAdapter(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"?>

android:layout_width="match_parent" android:layout_height="wrap_content">

android:id="@+id/checkedView"

android:layout_centerVertical="true"

android:layout_alignParentLeft="true"

android:layout_width="wrap_content"

android:layout_height="48dp" />

android:id="@+id/text"

android:gravity="center_vertical"

android:layout_alignParentRight="true"

android:layout_width="wrap_content"

android:layout_height="48dp" />

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

接下来,就是使用我封装的ChoiceListAdapter,来实现单选(或多选)的ListView,代码如下:listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

ChoiceListAdapter adapter = new ChoiceListAdapter(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图:

ce261470b65cc546a279b768bb55c73b.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值