Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義View(二)(Android群英傳)

自定義View(二)(Android群英傳)

編輯:關於Android編程

這篇介紹第二種自定義View方法,創建復合控件

創建復合控件

創建復合控件可以很好地創建出具有重用功能的控件集合。這種方式通常需要繼承一個合適的ViewGroup,再給它添加指定功能的控件,從而組合成新的復合控件。通過這種方式創建的控件,我們一般會給它指定一些可配置的屬性,讓它具有更強的拓展性。下面就以一個TopBar為示例,講解如何創建復合控件。
  我們知道為了應用程序風格的統一,很多應用程序都有一些共通的UI界面,比如下圖中所示的TopBar這樣一個標題欄。


界面上的TopBar

  通常情況下,這些界面都會被抽象出來,形成一個共通的UI組件。所有需要添加標題欄的界面都會引用這樣一個TopBar,而不是每個界面都在布局文件中寫這樣一個TopBar。同時,設計者還可以給TopBar增加響應的接口,讓調用者能夠更加靈活地控制TopBar,這樣不僅可以提高界面的復用率,更能在需要修改UI時,做到快速修改,而不需要對每個頁面的標題欄都進行修改。
  下面我們就來看看該如何創建一個這樣的UI模板。首先,模板應該具有通用性與可定制性。也就是說,我們需要給調用者以豐富的接口,讓他們可以更改模板中的文字、顏色、行為等信息,而不是所有的模板都一樣,那樣就失去了模板的意義。

定義屬性

  為一個View提供可自定義的屬性非常簡單,只需要在res資源目錄的values目錄下創建一個attrs.xml的屬性定義文件,並在該文件中通過如下代碼定義相應的屬性即可。

 

    
        
        
        
        
        
        
        
        
        
    

我們在代碼中通過標簽聲明了使用自定義屬性,並通過name屬性來確定引用的名稱。最後,通過標簽來聲明具體的自定義屬性,比如在這裡定義了標題文字的字體、大小、顏色,左邊按鈕的文字顏色、背景、字體,右邊按鈕的文字顏色、背景、字體等屬性,並通過format屬性來指定屬性的類型。這裡需要注意的就是,有些屬性可以是顏色屬性,也可以是引用屬性。比如按鈕的背景,可以把它指定為具體的顏色,也可以把它指定為一張圖片,所以使用“|”來分隔不同的屬性—-“reference|color”。
  在確定好屬性後,就可以創建一個自定義控件—-TopBar,並讓它繼承自ViewGroup,從而組合一些需要的控件。這裡為了簡單,我們繼承RelativeLayout。在構造方法中,通過如下所示代碼來獲取XML布局文件中自定義的那些屬性,即與我們使用系統提供的那些屬性一樣。

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);

系統提供了TypedArray這樣的數據結構來獲取自定義屬性集,後面引用的styleable的TopBar,就是我們在XML中通過所指定的name名。接下來,通過TypedArray對象的getString()、getColor()等方法,就可以獲取這些定義的屬性值,代碼如下所示。

// 通過這個方法,將你在attrs.xml中定義的declare-styleable的所有屬性值存儲到TypedArray中
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
// 從TypedArray中取出對應的值來為要設置的屬性賦值
mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
mLeftText = ta.getString(R.styleable.TopBar_leftText);
mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);
mRightText = ta.getString(R.styleable.TopBar_rightText);
mTitleTextSize = ta.getDimension(R.styleable.TopBar__titleTextSize, 10);
mTitleTextColor = ta.getColor(R.styleable.TopBar__titleTextColor, 0);
mTitle = ta.getString(R.styleable.TopBar__title);
// 獲取完TypedArray的值後,一般要調用recycle方法來避免重新創建時的錯誤
ta.recycle();

這裡需要注意的是,當獲取完所有的屬性值後,需要調用TypedArray的recycle方法來完成資源的回收。

組合控件

接下來,我們就可以開始組合控件了。UI模板TopBar實際上由三個控件組成,即左邊的點擊按鈕mLeftButton,右邊的點擊按鈕mRightButton和中間的標題欄mTitleView。通過動態添加控件的方式,使用addView()方法將這三個控件加入到定義的TopBar模板中,並給它們設置我們前面所獲取到的具體的屬性值,比如標題的文字顏色、大小等,代碼如下所示。

// 為創建的組件元素賦值
// 值就來源於我們在引用的xml文件中給對應屬性的賦值
mLeftButton.setTextColor(mLeftTextColor);
mLeftButton.setBackground(mLeftBackground);
mLeftButton.setText(mLeftText);

mRightButton.setTextColor(mRightTextColor);
mRightButton.setBackground(mRightBackground);
mRightButton.setText(mRightText);

mTitleView.setText(mTitle);
mTitleView.setTextColor(mTitleTextColor);
mTitleView.setTextSize(mTitleTextSize);
mTitleView.setGravity(Gravity.CENTER);

// 為組件元素設置相應的布局元素
mLeftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
mLeftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
// 添加到ViewGroup
addView(mLeftButton, mLeftLayoutParams);

mRightLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
mRightLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
addView(mRightButton, mRightLayoutParams);

mTitleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
mTitleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
addView(mTitleView, mTitleLayoutParams);

·定義接口
  在UI模板類中定義一個左右按鈕點擊的接口,並創建兩個方法,分別用於左邊按鈕的點擊和右邊按鈕的點擊,代碼如下所示。

// 接口對象,實現回調機制,在回調方法中
// 通過映射的接口對象調用接口中的方法
// 而不用去考慮如何實現,具體的實現由調用者去創建
public interface topbarClickListener {
    // 左按鈕點擊事件
    void leftClick();

    // 右按鈕點擊事件
    void rightClick();
}

·暴露接口給調用者
  在模板方法中,為左、右按鈕增加點擊事件,但不去實現具體的邏輯,而是調用接口中相應的點擊方法,代碼如下所示。

// 按鈕的點擊事件,不需要具體的實現,
// 只需調用接口的方法,回調的時候,會有具體的實現
mRightButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        mListener.rightClick();
    }
});
mLeftButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        mListener.leftClick();
    }
});

// 暴露一個方法給調用者來注冊接口回調
// 通過接口來獲得回調者對接口方法的實現
public void setOnTopbarClickListener(topbarClickListener mListener) {
    this.mListener = mListener;
}

·實現接口回調
  在調用者的代碼中,調用者需要實現這樣一個接口,並完成接口中的方法,確定具體的實現邏輯,並使用第二步中暴露的方法,將接口的對象傳遞進去,從而完成回調。通常情況下,可以使用匿名內部類的形式來實現接口中的方法,代碼如下所示。

mTopBar.setOnTopbarClickListener(new MyTopBar.topbarClickListener() {
    @Override
    public void leftClick() {
        Toast.makeText(MainActivity.this,
                "left", Toast.LENGTH_SHORT)
                .show();
    }
    @Override
    public void rightClick() {
        Toast.makeText(MainActivity.this,
                "right", Toast.LENGTH_SHORT)
                .show();
    }
});

這裡為了簡單演示,只顯示兩個Toast來區分不同的按鈕點擊事件。除了通過接口回調的方式來實現動態的控制UI模板,同樣可以使用公共方法來動態地修改UI模板中的UI,這樣就進一步提高了模板的可定制性,代碼如下所示。

/**
* 設置按鈕的顯示與否 通過id區分按鈕,flag區分是否顯示
*
 * @param id   id
* @param flag 是否顯示
*/
public void setButtonVisable(int id, boolean flag) {
    if (flag) {
        if (id == 0) {
            mLeftButton.setVisibility(View.VISIBLE);
        } else {
            mRightButton.setVisibility(View.VISIBLE);
        }
    } else {
        if (id == 0) {
            mLeftButton.setVisibility(View.GONE);
        } else {
            mRightButton.setVisibility(View.GONE);
        }
    }
}

通過如上所示代碼,當調用者通過TopBar對象調用這個方法後,根據參數,調用者就可以了動態地控制按鈕的顯示,代碼如下所示。

// 控制topbar上組件的狀態
mTopBar.setButtonVisable(0, true);
mTopBar.setButtonVisable(1, false);

引用UI模板

最後一步,自然是在需要使用的地方引用UI模板,在引用前,需要指定引用第三方控件的名字空間。在布局文件中,可以看到如下一行代碼。

xmlns:android="http://schemas.android.com/apk/res/android"

  這行代碼就是在指定引用的名字空間xmlns,即xml namespace。這裡指定了名字空間為“android”,因此在接下來使用系統屬性的時候,才可以使用“android:”來引用Android的系統屬性。同樣地,如果要使用自定義的屬性,那麼就需要創建自己的名字空間,在Android Studio中,第三方的控件都使用如下代碼來引入名字空間。

xmlns:custom="http://schemas.android.com/apk/res-auto"

  這裡我們將引入的第三方控件的名字空間取為custom,之後再XML文件中使用自定義的屬性時,就可以通過這個名字空間來引用,代碼如下所示。

使用自定義的View與系統原生的View最大的區別就是在申明控件時,需要指定完整的包名,而在引用自定義的屬性時,需要使用自定義的xmlns名字。
  再更進一步,如果將這個UI模板寫到一個布局文件中,代碼如下所示。

通過如上所示的代碼,我們就可以在其他的布局文件中,直接通過標簽來引用這個UI模板View,代碼如下所示。

這樣就更加滿足了我們的模板需求。
  運行程序後,顯示效果如下圖所示。


組合控件

  當調用公共方法setButtonVisable()來控制左右兩個按鈕的顯示和隱藏的時候,效果顯示如下圖所示。

隱藏右按鈕

項目地址→MyTopBar

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved