1. 程式人生 > >帶checkbox的ListView實現(二)——自定義Checkable控制元件的實現方法

帶checkbox的ListView實現(二)——自定義Checkable控制元件的實現方法

前言:前一篇文章給大家展示了傳統的Listview的寫法,但有的時候我們並不想在DataHolder類中加一個標識是否選中的checked的成員變數,因為在專案開發中,大部分的ListItemLayout佈局都是大家共用的,有些人根本不需要checkbox控制元件,所以會在初始化的時候把這個控制元件給隱藏掉,但我們的DataHolder在構造的時候以及ListItemAdapter在渲染的時候都需要checked變數,這就有點坑了,所以要想辦法能讓checkbox不與資料相關聯,可能我說到這大家都不大明白我在說什麼,其實我也感覺我沒講明白,沒關係,往下看,等這篇文章看完之後,如果還沒明白,那就給我留言吧。

相關文章:

同樣,還是先給大家看看效果圖:(與上篇的效果一樣,其實我就是用的上一篇的效果圖偷笑


同樣,我們還是從佈局開始講。

一、activity_main.xml ——MainActivity佈局檔案

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.harvic.trylistviewcheckbox.MainActivity" >

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="100dp"
        android:choiceMode="multipleChoice"
        android:dividerHeight="1px"
        android:scrollbars="none" />
    
    <Button android:id="@+id/all_sel"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="50dip"
        android:layout_gravity="bottom"
        android:text="全選"
        />
    <Button android:id="@+id/all_unsel"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="全部取消"/>
</FrameLayout>
注意啦:

這裡的佈局是與上一篇一樣一樣的,一個ListView兩個按鈕。但這裡有個引數必須要新增:

在ListView中:

android:choiceMode="multipleChoice"
這個很重要,android:choiceMode中有三個取值:none、singleChoice、multipleChoice;分別代表:不可選擇,單選和多選。在這裡,不同的取值對ListView的影響是不一樣的,但這個影響僅對ListView的Item自己帶有checkable屬性時才起作用,對於沒有checkable屬性的ListView是沒有任何效果的,比如,你把android:choiceMode這個引數放在上篇的程式碼中,無論你取什麼值都沒有任何作用,具體為什麼,下面再講。

二、check_list_item.xml —— 單個Item佈局

<?xml version="1.0" encoding="utf-8"?>

<com.harvic.trylistviewcheckbox.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="68dp">

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|center_vertical"
        android:button="@drawable/checkbox_selector"
        android:clickable="false"
        android:focusable="false" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="17dp"
        android:layout_marginTop="17dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/subtitle"
            android:textSize="12sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</com.harvic.trylistviewcheckbox.CheckableFrameLayout>
這裡與上一篇有兩個地方不同:

1、很明顯,使用的自定義控制元件CheckableFrameLayout;

2、CheckBox控制元件沒有定義ID值,如果根據上一篇的方式,大家可能會打個問號,沒有ID怎麼獲取這個控制元件,又怎麼讓它顯示選中與不選中呢。
下面看看自定義的控制元件類CheckableFrameLayout的實現:

package com.harvic.trylistviewcheckbox;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import android.widget.FrameLayout;

public class CheckableFrameLayout extends FrameLayout implements Checkable {

	public CheckableFrameLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	private boolean mChecked = false;

	@Override
	public void toggle() {
		setChecked(!mChecked);
	}

	@Override
	public boolean isChecked() {
		return mChecked;
	}

	@Override
	public void setChecked(boolean checked) {
		if (mChecked != checked) {
			mChecked = checked;
			refreshDrawableState();
			for (int i = 0, len = getChildCount(); i < len; i++) {
				View child = getChildAt(i);
				if(child instanceof Checkable){
					((Checkable) child).setChecked(checked);
				}
			}
		}
	}

}
因為我們用到的是FrameLayout控制元件,所以這裡派生自FrameLayout,如果用到諸如LinearLayout,RelativeLayout控制元件等,就要改成對應的類。最後還繼承了Checkable介面;

FrameLayout沒什麼好講的,就是幀佈局。關鍵問題在於Checkable介面,凡實現這個介面的控制元件都將具有可選中狀態的屬性;在普通控制元件中,具有這個狀態的有:CheckBox, CheckedTextView, CompoundButton, RadioButton, ToggleButton等。(《Android 中文API (33) —— Checkable》)對於如何展示它的選中狀態需要使用者自主實現三個函式:isChecked(),toggle(),setChecked();也就是說,當用戶使用ListView.setItemChecked(int position,bool checked)函式來將指定的Item設為Checked標識時,就會自動呼叫這裡的SetChecked()函式。在程式碼中,我們如何設計,使用者介面就會顯示怎樣的選中狀態;

把SetChecked()函式單獨拿出來看看:

public void setChecked(boolean checked) {
	if (mChecked != checked) {
		mChecked = checked;
		refreshDrawableState();
		for (int i = 0, len = getChildCount(); i < len; i++) {
			View child = getChildAt(i);
			if(child instanceof Checkable){
				((Checkable) child).setChecked(checked);
			}
		}
	}
}

由於CheckableFrameLayout在ListItem的佈局中有三個控制元件,兩個TextView和一個checkbox;所以當用戶設定點選屬性時,我們要將CheckableFrameLayout的子控制元件checkbox根據傳進來的checked引數更改當前的狀態,所以對它下面的所有子控制元件進行輪循,因為checkbox是具有checkable屬性的,所以如果此控制元件具有checkable屬性說明肯定會checkbox,就將它設定為使用者指定的checked狀態;

三、ViewHolder——ListItem對應的檢視類

public class ViewHolder{
	public TextView mTitle;
	public TextView mSubTitile;	
};
注意,這裡沒有了checkbox控制元件所對應的mCheckBox物件;

四、DataHolder——ListItem對應的資料類

package com.harvic.trylistviewcheckboxdata;

public class DataHolder{
	public String titleStr;
	public String subTitleStr;
	
	public DataHolder(String title,String subTitle){
		titleStr = title;
		subTitleStr = subTitle;		
	}
}
同樣,這裡有標識主標題文字的titleStr和標識副標題的subTitleStr;但沒有了標識選中狀態的checked變數,因為我們的控制元件選中的處理是listviewItem自己完成的。

五、ListItemAdapter

同樣,先列出全部程式碼,然後再看看有什麼不同。
package com.harvic.trylistviewcheckbox;

import java.util.List;

import com.example.trylistviewcheckbox.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ListitemAdapter extends BaseAdapter {

	private List<DataHolder> mList;
	private Context mContext;
	private LayoutInflater mInflater;
	public ListitemAdapter(Context context,List<DataHolder> list){
		mList = list;
		mContext = context;
		mInflater = LayoutInflater.from(context);
	}
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mList.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return mList.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder holder = null;  
        if (convertView == null) {  
              
            holder=new ViewHolder();    
              
            convertView = mInflater.inflate(R.layout.check_list_item, null);   
            holder.mTitle = (TextView)convertView.findViewById(R.id.title);  
            holder.mSubTitile = (TextView)convertView.findViewById(R.id.subtitle);  
            convertView.setTag(holder);  
              
        }else {  
              
            holder = (ViewHolder)convertView.getTag();  
        }  
           
        holder.mTitle.setText((String)mList.get(position).titleStr);  
        holder.mSubTitile.setText((String)mList.get(position).subTitleStr);  
        return convertView;  
	}
	
}
在渲染等等上基本一樣,唯一不同之處在於沒有了對checkbox控制元件的處理。

六、 MainActivity

先看看MainActivity的全部程式碼,然後慢慢講。
package com.harvic.trylistviewcheckbox;


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

import com.example.trylistviewcheckbox.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//構造資料
		final List<DataHolder> dataList = new ArrayList<DataHolder>();
		for(int i=0;i<10;i++){
			dataList.add(new DataHolder("harvic的blog------"+i,"harvic"));
		}
		//構造Adapter
		ListitemAdapter adapter = new ListitemAdapter(MainActivity.this, dataList);
		final ListView listView = (ListView)findViewById(R.id.list);
		listView.setAdapter(adapter);
		
		//全部選中按鈕的處理
		Button all_sel = (Button)findViewById(R.id.all_sel);
		Button all_unsel = (Button)findViewById(R.id.all_unsel);
		all_sel.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				for(int i=0;i<dataList.size();i++){
					listView.setItemChecked(i, true);
				}
			}
		});
		
		//全部取消按鈕處理
		all_unsel.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				for(int i=0;i<dataList.size();i++){
					listView.setItemChecked(i, false);
				}
			}
		});
	}

}
先看一下處理步驟:構造資料-》構造Adapter並設定

但!但!但!沒有listView.setOnItemClickListener()的設定!!!!!!!!!!!

到這裡大家可能要疑問了,為什麼沒有設計ItemClick的設定,它依然能處理checkbox的事件響應呢?當然是因為我們前面讓自定義的CheckableFrameLayout具有了標識可以選中狀態的Checkable介面,所以ListView的每一個Item現在都具有Checkbox的點選屬性,換句話說,我們的CheckableFrameLayout其實就是擴充套件的Checkbox控制元件!當然也可以對ListView設定OnItemClick事件監聽,用以處理Item項點選事件;

再看看全選按鈕的實現:

all_sel.setOnClickListener(new View.OnClickListener() {
	
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		for(int i=0;i<dataList.size();i++){
			listView.setItemChecked(i, true);
		}
	}
});
因為我們的每個ListViewItem都具有Checkable屬性,所以呼叫ListView的setItemChecked()函式是有作用的,如果我們的ListviewItem不具有Checkable屬性,那麼無論你怎麼呼叫SetItemChecked函式都不會起什麼效果!

全部取消也很簡單了,同樣是輪循所有的Item,然後把利用SetItemChecked(i,false)即可。

七、附:獲取所有選中行的行號

上面,我們基本實現了自定義控制元件實現自動選中checkbox的功能,但有時,我們在選中後,更需要知道,我們都選中了哪些,下面的程式碼就實現了這個功能:其中position就是獲取到了當前選中行的position

SparseBooleanArray checkedArray = mListView.getCheckedItemPositions();
for (int i = 0; i < checkedArray.size(); i++) {
    if (checkedArray.valueAt(i)){
        ……//i就是選中的行號
    }
}

OK啦 ,到這就全部講完了,對於自定義控制元件的這部分涉及的到東東比較多,不知道大家理解的怎麼樣,如果有哪部分沒理解的話,在評論中回覆下,我再修改內容。或許能直接給出應該怎麼組織本文的建議就更好不過了,謝謝。

如果本文有幫到你,記得加關注哦!

相關推薦

checkbox的ListView實現——定義Checkable控制元件實現方法

前言:前一篇文章給大家展示了傳統的Listview的寫法,但有的時候我們並不想在DataHolder類中加一個標識是否選中的checked的成員變數,因為在專案開發中,大部分的ListItemLayout佈局都是大家共用的,有些人根本不需要checkbox控制元件,所以會在初

網上購物系統Task007——定義DateList控制元件分頁顯示商品資訊

原始碼:13033480群共享 一、資料集Model新增商品資訊類ItemInfo.cs。 using System; namespace WestGarden.Model { public class ItemInfo { privat

Spring Boot實現OAuth 2.0-- 定義許可權驗證

自定義攔截器進行許可權驗證 涉及到的姿勢: 自定義註解 攔截器 Spring Boot新增攔截器 文章目錄: 自定義註解 @Target(ElementType.METHOD)//作用在方法 @Retention(RetentionP

MySQL數據庫高級——定義函數

MySQL 自定義 函數 MySQL數據庫高級(二)——自定義函數 一、自定義函數簡介 自定義函數 (user-defined function UDF)是一種對MySQL擴展的途徑,其用法和內置函數相同。自定義函數的兩個必要條件:A、參數B、返回值(必須有)。函數可以返回任意類型的值。 二、自定

函式計算搭建 Serverless Web 應用- 定義域名

摘要: 繫結自定義域名可以允許使用者通過自定義域名訪問 FC 的函式,配合 HTTP 觸發器使用,為使用函式計算搭建 Web 應用提供便利。 簡介阿里雲 函式計算(Function Compute) 是事件驅動的全託管計算服務,是阿里雲的 Serverless 計算平臺。基於函式計算構建應用,您無需管理伺服

SpringBoot之HandlerInterceptor攔截器的使用 ——定義註解

在上一篇部落格已經介紹了HandlerInterceptor的基本用法這裡就不重複了詳見:SpringBoot之HandlerInterceptor攔截器的使用 ——(一) 功能簡介 攔截所有添加了我們自定義的註解的方法,並將userId和userMobile放入HttpServ

關於資料序列化4定義序列化的實現,支援常用集合框架

下面的示例很好的揭示瞭如何實現自定義序列化的方法。 支援byte, byte[], boolean, boolean[], int, int[], long, long[] ,double ,double[], String, String[], 以及Enum, List,Map兩種包

CoordinatorLayout的使用——定義Behavior

 我們在上一篇文章CoordinatorLayout的使用(一)——簡單使用中介紹了CoordinatorLayout的基本用法。為什麼CoordinatorLayout能夠這麼方便的幫助我們非常簡單的就實現炫酷的UI互動效果呢?這就不得不提到它的內部類Behavior了。其實Coor

RecyclerView --- 定義LayoutManager

【記錄】記錄點滴 【需求】Recycler需要特殊排列順序時,要實現自定義LayoutManager 自定義大致分為三步:1. 放置全部的View;2. 滑動;3. 回收機制 1. RecyclerView繼承自ViewGroup,每個 item 就是它的子 view,

SpringBoot整合shiro定義sessionManager

傳統結構專案中,shiro從cookie中讀取sessionId以此來維持會話,在前後端分離的專案中(也可在移動APP專案使用),我們選擇在ajax的請求頭中傳遞sessionId,因此需要重寫shiro獲取sessionId的方式。自定義ShiroSessio

定義Imageview控制元件實現多種手勢操作 拖動、水平縮放、豎直縮放、等比例縮放、雙擊、長按

專案中需要使用自定義控制元件的多種手勢操作,之前在網上查閱資料的時候發現能找到的一般是隻實現了其中的幾種,這次就把我做的控制元件分享一下,人人為我,我為人人嘛,哈哈! 這個自定義控制元件實現的主要功能是控制元件的拖動和縮放(注意:不是對控制元件中的圖片進行操作,話說很多帖子

Emoji開源專案解讀定義表情

介紹 上一節呢,我們解讀了一個系統Emoji表情,這節呢, 我們談談自定義表情,如QQ、微信等,正好前兩天看到一個仿QQ的一個應用,雖然還是有許多需要完善的地方, 不過對於自定義Emoji表情功能,做的也是比較成熟了,這裡要謝謝白玉樑同學,下面我帶領大家來一起學習一下他的

WPF中的事件- 定義路由事件

自定義路由事件的新增,共分為三個步驟: 1、宣告並註冊路由事件 2、為路由事件新增CLR事件包裝 3、建立可以激發路由事件的方法 以下例項,實現的功能是建立一個Button,每次點選該Button時激發自定義的路由事件ReportTime,傳遞按鈕被點

使用WiX Toolset建立.NET程式釋出Bootstrapper安裝策略管理——定義安裝

自定義產品解除安裝方式         繼續從上一次的基礎上前進,現在我們已經知道了最簡單的bootstrapper打包方法,現在我們對其中的每個節點深入自定義,爭取可以達到我們需要的效果。先把最後全部的XML貼出來。 <?xml version="1.0" en

zabbix學習定義模板建立-1

一、建立一個主機(1)主機名稱要和客戶端配置檔案中的zabbix_agentd.conf中hostname一致。(2)agent代理程式介面的ip地址填寫客戶端的ip二、建立模板(功能為監控uptime的輸出資訊)(1)監控指令碼如下#!/bin/bash function

Android 音樂播放器的實現定義按鈕的實現

Android 系統提供了MediaPlayer控制元件,讓我們能夠利用它實現音訊的播放。 而從學Android開始,在看教程的時候,我就想,我要自己做一個音樂播放器,因為一個完整的音樂播放器是有很多功能的,它涉及到很多方面的知識,可以幫助我們更好地學習和掌握關於Andro

Java 異常 定義異常

 Java 異常(二) 自定義異常 在開發中,為了適應業務的開發需求, 在 Java 中可以根據業務的異常情況自定義異常。 一、自定義異常 所有的自定義異常都必須是 Throwable 的子類,在自定義繼承時可以繼承於 Exception 或者它的子類。 二、自定義異常的分類 1、檢查性異

Bootstrap Blazor 元件介紹 Table 定義模板列功能介紹

Bootstrap Blazor 是一套企業級 UI 元件庫,適配移動端支援各種主流瀏覽器,已經在多個交付專案中使用。通過本套元件可以大大縮短開發週期,節約開發成本。目前已經開發、封裝了 70 多個元件,歡迎有興趣的同學試用。 Gitee 開源地址為:https://gitee.com/LongbowEnt

定義控制元件 實現一個繞圓圈的箭頭

自定義的類 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import

定義FlowLayout控制元件實現定義寬度並換行

最近的需求是實現新增購物車頁面,展示規格的時候會出現顯示不全,資料會自動剪下掉,後邊重新自定義了FlowLayout問題得到解決,下面直接上程式碼 public class FlowLayoutView extends ViewGroup { private final int DE