1. 程式人生 > >Android自定義控制元件——自定義組合控制元件

Android自定義控制元件——自定義組合控制元件

       前面幾篇博文介紹了Android如何自定義控制元件,其實就是講一下如何“從無到有”的自定義一個全新的控制元件,繼承View或者繼承ViewGroup,複寫其相關方法,這種自定義控制元件的方式相對來說難度較大,而且並不是所有需要新控制元件的情況下,都要這樣進行。有很多情況下,我們只要運用好Android給我提供好的控制元件,經過佈局巧妙的結合在一起,就是一個新的控制元件,我稱之為“自定義組合控制元件”。

       那麼,這種自定義組合控制元件在什麼情況下用呢?或者大家在做專案時候會發現,某些佈局會被重複的利用,同一個佈局的XML程式碼塊會被重複的複製黏貼多次,這樣會造成程式碼結構混亂不說,程式碼量也會增大,各種控制元件都需要在Java程式碼中被申明和處理相應的邏輯,工作量著實不小,所以,必須要找到一個合理的“偷懶”的方式,開動腦經去怎麼簡化以上說的不必要的麻煩。下面看一張圖,就一個簡單的佈局,我們就此圖來實現一個簡單的自定義組合控制元件。


        從上面的圖來分析,我們可以看到,這個佈局裡面是沒有“全新”的控制元件的,用的都是Android系統原生的控制元件。熟悉Android介面佈局的人,肯定覺得這種佈局真是小Case,太簡單了,分分鐘就可以寫完。於是下面就是某一個條目的佈局程式碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_show_address"
    android:layout_width="match_parent"
    android:layout_height="60dip"
    android:background="@drawable/selector_blue" >

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dip"
        android:layout_marginTop="1dip"
        android:text="這是標題"
        android:textColor="#000000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_title"
        android:layout_marginLeft="6dip"
        android:layout_marginTop="1dip"
        android:text="這是描述內容"
        android:textColor="#99ff0000"
        android:textSize="14sp" />

    <CheckBox
        android:id="@+id/cb_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:clickable="false"      
        android:focusable="false" />
    
    <!-- 加一條分割線 -->
    <View 
        android:layout_marginTop="7dip"
        android:layout_alignParentBottom="true"
        android:layout_alignBottom="@id/cb_status"
        android:layout_width="match_parent"
        android:layout_height="0.2dip"
        android:background="#000000"/>

</RelativeLayout>
       可以看到,這種佈局確實相當的簡單。但是,這時候產品經理告訴你,需求改了,我們需要在這個介面再加一個這樣的條目,於是你覺得,小意思,Ctrl+C,Ctrl+V,輕鬆搞定,然後改一下控制元件的id,在Java程式碼中findviewbyid(id),加一段邏輯程式碼,搞完收工。沒想到這時候產品又來了,需求改了,這裡需要加10個這樣的佈局,於是你...誠然,這時候再Ctrl+C,Ctrl+V是不合適的,工作量就顯得很大了,即使你不嫌麻煩的話,照樣做了,你料不到產品會再來,那個給我刪掉幾個,那個再加上幾個,是不是要瘋了。

       也許,我們可以相出一個偷懶的方法來呢。通過分析上面的佈局,可以發現,佈局上每一個子條目是不變的,佈局完全一樣,唯一在變化的是,紅色的TextView上的文字隨著CheckBox的狀態再改變著,而這種變化,我們是否可以想辦法抽取到某個方法中呢,答案是肯定能的。我們可以將這種子條目的佈局一次性封裝到一個Java類中,每次呼叫這個控制元件的時候,事先設定各種屬性資料即可,這裡涉及到了自定義屬性了,關於自定義屬性,可以參考我的上一篇部落格,

Android自定義控制元件——自定義屬性,在這裡就不在贅述了。分析一下這個屬性集該怎麼定義,從上面的圖片可以看出,控制元件上需要設定的內容分別是,上面TextView的標題,還有下面TextView的描述資訊,且描述資訊是根據CheckBox的狀態發生改變的,所以這兩種狀態(true或false)都需要被定義到屬性集裡去,於是屬性集就有了。

    在工程下的res/values目錄下,新建attrs.xml檔案,定義如下屬性集:

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

    <declare-styleable name="combinationView">
        <attr name="desc_on" format="string"></attr>
        <attr name="desc_off" format="string"></attr>
        <attr name="title" format="string"></attr>
    </declare-styleable>

</resources>

       定義好了屬性集了,接下來我們就需要定義一個Java類,來渲染這段佈局,解析這個屬性集,並且物件提供修改控制元件狀態的方法,已達到複用的效果。問題來了,我們定義的這個Java類需要繼承哪個類呢?在這裡,我們不必考慮View了,因為這裡不是全新自定義控制元件,不需要onMessure和onDraw去測量去畫一個檢視。那麼ViewGroup呢?我們也不必用這個類,因為這裡的佈局是給定好的,不需要使用onLayout給子控制元件設定顯示的位置。那麼,該繼承什麼呢?我們可以想象一下ViewGroup的子類是不是可以呢?實現自定義控制元件的除了繼承View和ViewGroup之外,還可以直接繼承Android已有的控制元件進行修改,這個用面向物件的思想,應該不難想象吧。由於,該佈局檔案用的相對佈局RelativeLayout,我們想當然可以自定義Java類去繼承這個RelativeLayout,RelativeLayout裡提供一些引數和方法方便我們去實現子控制元件的佈局。但是,我們這裡直接在子控制元件佈局已經寫好了,不需要使用RelativeLayout提供的引數和方法來佈局了。所以,導致了,即使不去繼承RelativeLayout,而改成LinearLayout,FrameLayout...也是可以的,只要這個佈局類是ViewGroup的子類就行。以下是這個自定義組合控制元件的實現程式碼:

package com.example.combinationview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class CombinationView extends RelativeLayout {

	private TextView tv_title;
	private TextView tv_desc;
	private CheckBox cb_status;
	// 名稱空間,在引用這個自定義元件的時候,需要用到
	private String namespace = "http://schemas.android.com/apk/res/com.example.combinationview";
	// 標題
	private String title;
	// 被選中的描述
	private String desc_on;
	// 未被選中的描述
	private String desc_off;

	public CombinationView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 將自定義組合控制元件的佈局渲染成View
		View view = View.inflate(context, R.layout.layout_combinationview, this);
		tv_title = (TextView) view.findViewById(R.id.tv_title);
		tv_desc = (TextView) view.findViewById(R.id.tv_desc);
		cb_status = (CheckBox) view.findViewById(R.id.cb_status);

		title = attrs.getAttributeValue(namespace, "title");
		desc_on = attrs.getAttributeValue(namespace, "desc_on");
		desc_off = attrs.getAttributeValue(namespace, "desc_off");
		System.out.println(title + ":" + desc_on + ":" + desc_off);
		// 初始化到子控制元件
		if (title != null) {
			tv_title.setText(title);
		}
		if (desc_off != null) {
			tv_desc.setText(desc_off);
		}
	}

	/**
	 * 判斷是否被選中
	 * 
	 * @return
	 */
	public boolean isChecked() {
		return cb_status.isChecked();
	}

	/**
	 * 設定選中的狀態
	 * 
	 * @param isChecked
	 */
	public void setChecked(boolean isChecked) {
		cb_status.setChecked(isChecked);
		if (isChecked) {
			tv_desc.setText(desc_on);
		} else {
			tv_desc.setText(desc_off);
		}
	}

}
       程式碼很簡單,首先繼承RelativeLayout,複寫其構造方法,在構造方法中先渲染布局的檢視,然後讀取屬性集的屬性,將預設顯示的屬性顯示到佈局上的子控制元件上即可。另外,還要對外提供一個判斷狀態的方法isChecked()來判斷該控制元件是否被選中了,提供一個設定狀態的方法setChecked(boolean),用來改變狀態。PS:為了驗證我上面的一段話,讀者可以將繼承RelativeLayout,改為繼承LinearLayout或者繼承FrameLayout,執行試試看,也是可以實現的。

       下面是引用這個自定義組合控制元件的方法,首先需要在Activity的佈局檔案中定義出來:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:example="http://schemas.android.com/apk/res/com.example.combinationview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.combinationview.CombinationView
        android:id="@+id/cv_first"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        example:desc_off="我是未被選中的描述1"
        example:desc_on="我是被選中的描述1"
        example:title="我是標題1" >
    </com.example.combinationview.CombinationView>

    <com.example.combinationview.CombinationView
        android:id="@+id/cv_second"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        example:desc_off="我是未被選中的描述2"
        example:desc_on="我是被選中的描述2"
        example:title="我是標題2" >
    </com.example.combinationview.CombinationView>

    <com.example.combinationview.CombinationView
        android:id="@+id/cv_third"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        example:desc_off="我是未被選中的描述3"
        example:desc_on="我是被選中的描述3"
        example:title="我是標題3" >
    </com.example.combinationview.CombinationView>

    <com.example.combinationview.CombinationView
        android:id="@+id/cv_fourth"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        example:desc_off="我是未被選中的描述4"
        example:desc_on="我是被選中的描述4"
        example:title="我是標題4" >
    </com.example.combinationview.CombinationView>

</LinearLayout>
首先在上面定義了四個自定義組合控制元件,大家可以看到,程式碼精簡多了不是?!需要注意的地方:這裡引用了自定義的屬性集,所以在佈局節點上必須要加上名稱空間
 xmlns:example="http://schemas.android.com/apk/res/com.example.combinationview"
其中,example是名稱空間的名稱,是任意取的,但是必須在控制元件中引用屬性的名稱一致,不然會報錯。後面的一串是標明屬性集的路徑,前半部分是固定的,最後一個“/”後面的內容必須是工程的包名,否則報錯。

       下面是Activity裡面的業務邏輯程式碼,沒什麼好說的

package com.example.combinationview;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener {

	private CombinationView cv_first;
	private CombinationView cv_second;
	private CombinationView cv_third;
	private CombinationView cv_fourth;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		cv_first = (CombinationView) findViewById(R.id.cv_first);
		cv_second = (CombinationView) findViewById(R.id.cv_second);
		cv_third = (CombinationView) findViewById(R.id.cv_third);
		cv_fourth = (CombinationView) findViewById(R.id.cv_fourth);
		cv_first.setOnClickListener(this);
		cv_second.setOnClickListener(this);
		cv_third.setOnClickListener(this);
		cv_fourth.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.cv_first:
			if (cv_first.isChecked()) {
				cv_first.setChecked(false);
			} else {
				cv_first.setChecked(true);
			}
			break;
		case R.id.cv_second:
			if (cv_second.isChecked()) {
				cv_second.setChecked(false);
			} else {
				cv_second.setChecked(true);
			}
			break;
		case R.id.cv_third:
			if (cv_third.isChecked()) {
				cv_third.setChecked(false);
			} else {
				cv_third.setChecked(true);
			}
			break;
		case R.id.cv_fourth:
			if (cv_fourth.isChecked()) {
				cv_fourth.setChecked(false);
			} else {
				cv_fourth.setChecked(true);
			}
			break;
		default:
			break;
		}
	}

}
        好了,關於自定義組合控制元件就講完了,非常簡單,但是比較常用。以後在專案用到時,想想實現步驟,自定義一種的組合的控制元件,用起來確實比較方便,比單純的複製黏貼不僅高大上,而且提高程式碼的複用性,簡化了程式碼的結構和減少了程式碼量。

相關推薦

android開發:定義組合控制元件

內容介紹 本文記錄,自定義組合控制元件,為了可以程式碼複用,減少程式碼量 配置控制元件屬性檔案 開啟res/values/目錄下的arss.xml檔案,新增下面屬性程式碼,如果沒有建立arrs.xml檔案。 <?xml version="1.0" enc

android-定義組合控制元件(EditText+選項)

一.前言 在開發中,或許一個業務需求中會出現很多系統控制元件組合成的佈局,並且經常需要複用。比如在一個表單中,裡面有個編輯框EditText右側還需要有個選項卡按鈕,需要有編輯框的輸入功能也需要有右側選項卡的點選事件,同時這兩個控制元件也存在一定關聯,且在一個介

android定義組合控制元件

---------------setting_item---------------<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.an

android:定義view--組合控制元件

專案中用到了很多類似的介面,一行左右兩邊都是顯示文字,數量非常多; 如果按照普通的方法畫肯定也能非常輕鬆的畫出來,但是因為使用地方較多,為了後期維護,程式碼的簡介,提高開發效率,簡單易用等等:可以自定義一個組合控制元件; 自定義組合控制元件使用起來非常方便,建立也非常的簡

android 定義組合控制元件 頂部導航欄

    在軟體開發過程中,經常見到,就是APP 的標題欄樣式幾乎都是一樣的,只是文字不同而已,兩邊圖示不同。為了減少重複程式碼,提高效率, 方便大家使用,我們把標題欄通過組合的方式定義成一個控制元件。 例下圖:                                

Android定義View之組合控制元件 ---- LED數字時鐘

先上圖 LEDView效果如圖所示。 之前看到一篇部落格使用兩個TextView實現了該效果,於是我想用自定義控制元件的方式實現一個LEDView,使用時即可直接使用該控制元件。 採用組合控制元件的方式,將兩個TextView疊放在一起,再使用digital-7.ttf字

Android定義控制元件——定義組合控制元件

       前面幾篇博文介紹了Android如何自定義控制元件,其實就是講一下如何“從無到有”的自定義一個全新的控制元件,繼承View或者繼承ViewGroup,複寫其相關方法,這種自定義控制元件的方式相對來說難度較大,而且並不是所有需要新控制元件的情況下,都要這樣進行

android定義控制元件(組合控制元件)相關

自定義元件及根據需求定義符合要求的控制元件 自定義控制元件流程: 一、繼承相應View,如:TextView  ImageView; 組合控制元件一般繼承ViewGroup,如:LinearLayout etc. 二、構造方法: public ArrowIndicatorV

Android定義組合控制元件之實現CheckBox變化

前言:自定義組合控制元件最大的好處就是複用性,可以為我們節省不少程式碼量,但是一般我們自定義組合控制元件的時候,封裝出來的控制元件不管是自己用還是別人用也好,封裝的程式碼最好是易讀性強,便於修改,沒有必要封裝太多的屬性,一般控制在兩三個屬性為最佳,畢竟我們不是Google.

Android定義view組合控制元件解析

##使用場景 在開發中,或許一個業務需求中會出現很多系統控制元件組合成的佈局,並且經常需要複用。 比如下圖中 qq或者微博的title欄,在一款app中,可能不同的介面 類似的view要出現很多次,這個時候 就可以設計自己的view控制元件,就稱為組合控制元件

Android定義控制元件---組合控制元件(包括定義屬性)

今天和大家分享下組合控制元件的使用。很多時候android自定義控制元件並不能滿足需求,如何做呢?很多方法,可以自己繪製一個,可以通過繼承基礎控制元件來重寫某些環節,當然也可以將控制元件組合成一個新控制元件,這也是最方便的一個方法。今天就來介紹下如何使用組合控制元件,

android 定義組合控制元件

1.要實現這個效果,用多個控制元件組合起來,要用到自定義控制元件 程式碼實現 1.自己寫一個佈局檔案 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android

android定義控制元件(五) 定義組合控制元件

< ?xml version="1.0" encoding="utf-8"?>    < LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"    android:layout_widt

android定義組合控制元件圖片輪播+小圓點+點選跳轉廣告頁面

1.寫一個佈局,用於自定義組合控制元件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/and

定義組合控制元件:Banner、輪播圖、廣告欄控制元件

1. 專案概述 這裡,我們使用自定義組合控制元件實現一個自動輪播的廣告條,也叫輪播圖,完整版的效果圖如下圖所示。其實,這就是我們經常見到的滾動廣告,預設情況下每隔N 秒會自動滾動,用手指左右滑動時也會切換到上一張或者下一張。當介面切換時,對應廣告圖片的標題也會

Android定義控制元件 --- 定義屬性 列舉值(固定屬性值)

今天寫一個自定義控制元件,為了提高使用者使用效率,需要對一個屬性的所有可能屬性值進行列舉(即,只能選擇使用給出的屬性值) 查了很多資料,自己總結一下。 如何寫自定義控制元件就不在贅述了,網上很多大神寫的都很好,此處只說明這一種情況。 attrs.xml <?xml

Android筆記--簡單的定義View之控制元件

第一步:新建atts.xml檔案,自定義屬性,不引用系統的屬性,在構造器中使用安卓系統自帶的API的TypedArray類取出atts.xml中的自定義屬性使用(通過對映)。 第二步:新建一個類,繼承

VB.NET學習筆記:WinForm定義DataGridView分頁組合控制元件

測試環境:windows 7和Microsoft Visual Studio 2015 點選下載本文資源 VB.NET雖然提供了大量控制元件供我們使用,但很多控制元件僅提供最基礎的功能。比如用DataGridView控制元件可以非常方便顯示或操作資料庫資料, 但卻沒有分頁功能。本文

定義組合控制元件

com.hybunion.customview.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import and

Android定義載入等待Dialog彈窗控制元件(仿ios效果實現)

效果圖 使用說明 1、專案下的build.gradle新增 allprojects { repositories { ... maven { url 'https://www.ji