1. 程式人生 > >Android學習之 自定義屬性及TypedArray的用法

Android學習之 自定義屬性及TypedArray的用法

  一、 背景說明:

          在xml檔案裡定義控制元件的屬性,我們用的最多的是 Android系統自帶的屬性如:

<ImageView
            android:id="@+id/iv_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@null"
            android:src="@drawable/ic_ms_quick_order" />
            

這裡小呂將自我學習與分享如何自定義屬性<通常在自定義控制元件中會被使用到>,在xml佈局檔案中 如:

<!-- 搜尋 -->
     <com.ice.view.menubutton.MyMenuButton 
        xmlns:ice="http://schemas.android.com/apk/res/com.ice.view.menubutton"
        android:id="@+id/btn_search"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ice:menuIcon="@drawable/ic_ms_search"
        ice:menuText="@string/ms_search"
        ice:textSize="14sp"
        ice:textColor="@color/orange" 
        ice:btnCode="search" />
        說明:1. 上面的MyMenuButton 是我自定義的一個選單按鈕控制元件  <圖片和文字的組合控制元件>。

                  2. xmlns:ice=http://schemas.android.com/apk/res/com.ice.view.menubutton  

                    是我自定義的名稱空間   名稱空間的名字可以自己隨便定義 ,這裡我定義的是ice  及 xmlns:ice 。

                    注意:
                       後面的地址則有限制,

                       其開始必須為:"http://schemas.android.com/apk/res/",後面則是包名com.ice.view.menubutton, 

                       此處的包名與AndroidManifest.xml中

                      <manifest>節點的屬性package="com.ice.view.menubutton"一致,不是自定義控制元件Java程式碼所在的包。

3. menuIcon / menuText / textSize / textColor / btnCode 就是我自定義的屬性。

                     <只針對自定義控制元件 MyMenuButton有效>。

二、關於該自定義控制元件的開發和xml佈局檔案的配置大致步驟如下: 

1、首先在res/values檔案下定義一個attrs.xml檔案.定義控制元件的自定義屬性集合   程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name ="MyMenuButton">
        <!-- 圖示 -->
        <attr name="menuIcon" format="reference" />
        <!-- 文字 -->
        <attr name="menuText" format="reference" />
        <!-- 文字大小 -->
        <attr name="textSize" format="dimension" />
        <!-- 字型顏色 -->
        <attr name="textColor" format="color" />
        <!-- 頁面編號 -->
        <attr name="btnCode">
            <flag name="quickOrder" value="0"></flag>
            <flag name="orderManager" value="1"></flag>
            <flag name="favorite" value="2"></flag>
            <flag name="search" value="3"></flag>
        </attr>   
    </declare-styleable>
    
</resources>

說明: 1.declare-styleable 是定義自定義屬性集合名稱的節點元素

            2.format可選項 

               "reference"//引用 
               "color"//顏色 
               "boolean"//布林值 
               "dimension"//尺寸值 
               "float"//浮點值 
               "integer"//整型值 
               "string"//字串 
               "fraction"//百分數,比如200% 

            3.元素節點 attr 定義各自定義屬性名稱   format用來定義屬性值的型別值,可以指定多種型別值如:

                 <attr name = "background" format ="reference|color" />       

            4.列舉值,格式如下: 
              <attrn ame="orientation"> 
                   <enum name="horizontal" value="0" /> 
                  <enum name="vertical" value="1" /> 
             </attr>   
             xml中使用時: 
             android:orientation= "vertical" 

           5.標誌位,位或運算,格式如下:

<!-- 頁面編號 -->
        <attr name="btnCode">
            <flag name="quickOrder" value="0"></flag>
            <flag name="orderManager" value="1"></flag>
            <flag name="favorite" value="2"></flag>
            <flag name="search" value="3"></flag>
        </attr>

        Xml中使用時:

             ice:btnCode="search"

        2.在res/layout檔案下新建自定義控制元件的xml佈局檔案:ms_menu_button.xml    程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:orientation="vertical" 
        android:background="@null" >
        
        <!-- 圖示 -->
        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@null"
            android:src="@drawable/ic_ms_quick_order" />

        <!-- 文字 -->
        <TextView
            android:id="@+id/tv_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/ms_quick_order" />
        
    </LinearLayout>

</RelativeLayout>

       3.自定義控制元件java類:MyMenuButton.java  <核心程式碼>
package com.ice.view.menubutton;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
 * 自定義 選單按鈕
 * @author ice
 *
 */
public class MyMenuButton extends RelativeLayout {

	private static final String TAG = "MyMenuButton";
	RelativeLayout relativeLayout;
	ImageView iv_icon;
	TextView tv_text;
	
	private Drawable menuIcon;
	private CharSequence menuText;
	private float textSize;
	private int textColor;
	private int btnCode;

	private static final int PAGE_CODE_QUICK_ORDER = 0;  // 快速訂單
	private static final int PAGE_CODE_ORDER_MANAGER = PAGE_CODE_QUICK_ORDER + 1;   // 訂單管理
	private static final int PAGE_CODE_FAVORITE = PAGE_CODE_ORDER_MANAGER + 1;    // 我的收藏
	private static final int PAGE_CODE_SEARCH = PAGE_CODE_FAVORITE + 1;   // 快速查詢
	
	public MyMenuButton(Context context) {
		this(context,null);
	}

	public MyMenuButton(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	
	public MyMenuButton(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		Log.d(TAG, "自定義元件構造方法MyMenuButton(...)  invoke");
		// 獲取所有自定義屬性組
		TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyMenuButton, defStyle, 0);
		// 獲取自定義元件所在佈局檔案中的自定義屬性值
		menuIcon = typedArray.getDrawable(R.styleable.MyMenuButton_menuIcon);
		menuText = typedArray.getText(R.styleable.MyMenuButton_menuText);
		// 設定當沒有設定textSize屬性值時    預設字型大小為14px   注意這裡的單位是px
		textSize = typedArray.getDimension(R.styleable.MyMenuButton_textSize, 14);
		textColor = typedArray.getInt(R.styleable.MyMenuButton_textColor, 0XFFFFFFFF);
		btnCode = typedArray.getInt(R.styleable.MyMenuButton_btnCode, PAGE_CODE_QUICK_ORDER);
		
		relativeLayout = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.ms_menu_button, this, true);
		
		// TypedArray 通常最後呼叫 .recycle() 方法,為了保持以後使用該屬性一致性!
		typedArray.recycle();
	}
	

	/**
     * 當View中所有的子控制元件均對映成XML後觸發 
	 */
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		Log.d(TAG, "onFinishInflate invoke");
		iv_icon = (ImageView) relativeLayout.findViewById(R.id.iv_icon);
		tv_text = (TextView) relativeLayout.findViewById(R.id.tv_text);
		
		iv_icon.setImageDrawable(menuIcon);
		tv_text.setText(menuText);
		tv_text.setTextColor(textColor);
		tv_text.setTextSize(textSize);
		Log.d(TAG, "menuText: "+menuText+" | textSize: "+textSize);
		
		this.setOnClickListener(new OnClickEvent());
	}
	
	
	
	class OnClickEvent implements OnClickListener{

		@Override
		public void onClick(View v) {
			switch (btnCode) {
			case PAGE_CODE_QUICK_ORDER:
				Log.d(TAG, "快速下單MenuButton被點選");
				break;

            case PAGE_CODE_ORDER_MANAGER:
            	Log.d(TAG, "訂單管理MenuButton被點選");
				break;
				
            case PAGE_CODE_FAVORITE:
            	Log.d(TAG, "我的收藏MenuButton被點選");
            	break;
				
            case PAGE_CODE_SEARCH:
            	Log.d(TAG, "搜尋MenuButton被點選");
            	break;
			}
		}
	}
	
	
}

        4.測試展示Activity:MainActivity.java     程式碼如下:
package com.ice.view.menubutton;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
	private static final String TAG = "MainActivity";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.d(TAG, "Before setContentView()...");
		setContentView(R.layout.activity_main);
		Log.d(TAG, "After setContentView()...");
	}

	
}

        5.測試展示佈局檔案:activity_main.xml      程式碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/bg_ms_menu"
    android:gravity="bottom"
    android:orientation="horizontal"
    android:paddingLeft="10dp"
    android:paddingRight="10dp" >

    <!-- 快速下單 -->
    <com.ice.view.menubutton.MyMenuButton 
        xmlns:ice="http://schemas.android.com/apk/res/com.ice.view.menubutton"
        android:id="@+id/btn_quick_order"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ice:menuIcon="@drawable/ic_ms_quick_order"
        ice:menuText="@string/ms_quick_order"
        ice:textColor="@android:color/black" 
        ice:btnCode="quickOrder"/>
        
     <!-- 訂單管理 -->
     <com.ice.view.menubutton.MyMenuButton 
        xmlns:ice="http://schemas.android.com/apk/res/com.ice.view.menubutton"
        android:id="@+id/btn_order_manager"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ice:menuIcon="@drawable/ic_ms_order_manager"
        ice:menuText="@string/ms_order_manager"
        ice:textColor="@color/green" 
        ice:btnCode="orderManager" />
     
     <!-- 我的收藏 -->
     <com.ice.view.menubutton.MyMenuButton 
        xmlns:ice="http://schemas.android.com/apk/res/com.ice.view.menubutton"
        android:id="@+id/btn_my_favorite"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ice:menuIcon="@drawable/ic_ms_my_favorite"
        ice:menuText="@string/ms_my_favorite"
        ice:textColor="@color/red" 
        ice:textSize="14px"
        ice:btnCode="favorite" />
     
     <!-- 搜尋 -->
     <com.ice.view.menubutton.MyMenuButton 
        xmlns:ice="http://schemas.android.com/apk/res/com.ice.view.menubutton"
        android:id="@+id/btn_search"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        ice:menuIcon="@drawable/ic_ms_search"
        ice:menuText="@string/ms_search"
        ice:textSize="14sp"
        ice:textColor="@color/orange" 
        ice:btnCode="search" />  
     
</LinearLayout >

       6.執行效果:


--------------》 哈哈  這裡搜尋menuButton怎麼那麼另類呢、呵呵  這是小呂故意的   詳細請看activity_main.xml和MyMenuButton.java程式碼說明。

        7.點選自定義選單控制元件  後臺日誌資訊如下:


說明:這裡我們可以看到自定義元件、onFinishInflate()方法的執行情況。