Android中如何為自定義控件增加狀態?


  

在android開發中我們常常需要對控件進行相關操作,雖然網上已有很多對控件酷炫的操作,但小編今天給大家分享的純屬實用出發。在查看了一些列安卓教程和文檔后,發現了一位大牛分享的非常不錯的有關android自定義控件增加狀態的文章,分享給大家,學習、參考。

 

 

場景

 

View類是Android UI組件的基礎構建模塊,主要負責組件的繪制及事件的處理。我們在一些自定義控件的場合,可能需要在一個組件上畫些東西,也是通過重寫View的onDraw方法,通過其參數的Canvas對象進行繪制。

 

我們學習<selector/>的時候,就知道了關於一個視圖組件會有許多種狀態,比如按下(pressed),選擇(selected),可用(enabled),正常狀態,其他狀態等等。View也處理了關於一個組件在不同狀態下的顯示的繪制邏輯,通常繼承自View的組件都有着以上所說的這些狀態。但是也有一些狀態是View沒有提供的,而我們可能正需要它們,所以就需要對狀態進行擴展,增加我們的狀態,比如增加checked。

 

這里有一個具體的場景:

 

這是一個開關按鈕,開關狀態下背景不同,文字不同,文字旁邊的圖片也不同。狀態我用checked,文字我定義了兩個屬性:onText以及offText,文字旁邊的圖片我打算只用一個foreground屬性,但需要寫一個selector來定義正常狀態(未鎖)和checked狀態(鎖定)下的圖片。

 

 

實現

 

首先寫一個類繼承自TextView,因為我打算用TextView的setCompoundDrawables來設定文字旁邊的圖片。

 

然后定義屬性:

 

    <declare-styleable name="ToggleView">

        <attr name="android:foreground"/>

        <attr name="pwOnText"/>

        <attr name="pwOffText"/>

        <attr name="pwColor"/>

        <attr name="pwDrawableHeight"/>

    </declare-styleable>

 

讀取屬性:

 

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToggleView);

        stateListDrawable = (StateListDrawable) a.getDrawable(R.styleable.ToggleView_android_foreground);

        colorStateList = a.getColorStateList(R.styleable.ToggleView_pwColor);

        offText = a.getString(R.styleable.ToggleView_pwOffText);

        onText = a.getString(R.styleable.ToggleView_pwOnText);

        drawableHeight = a.getDimensionPixelSize(R.styleable.ToggleView_pwDrawableHeight, 0);

        a.recycle();

 

 

通過在類中實現Checkable接口,可以完成選中的邏輯,但是畫出來的狀態卻沒有更新,所以接下來的實現過程就是本篇的主要內容:

 

首先定義狀態集:

 

    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};

 

然后我們要把狀態給加進去。我們需要重寫protected int[] onCreateDrawableState(int extraSpace)方法,如下:

 

    @Override

    protected int[] onCreateDrawableState(int extraSpace) {

        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);

        if (isChecked) {

            mergeDrawableStates(drawableState, CHECKED_STATE_SET);

        }

        return drawableState;

    }

 

先調用父類的onCreateDrawableState方法得到狀態數組對象drawableState,但是參數extraSpace要加上1,因為我們要往里面增加一個狀態。然后判斷在代碼邏輯中,是否為選中狀態,如果是的話,調用mergeDrawableStates(drawableState, CHECKED_STATE_SET)方法把我們的狀態值給加進去,最終返回drawableState。

 

但是我們雖然實現了Checkable接口,在設置狀態時卻沒有觸發到這個狀態。所以我們需要自己去觸發這個狀態。

 

    @Override

    public void setChecked(boolean checked) {

        if (isChecked != checked) {

            isChecked = checked;

            refreshDrawableState();

        }

    }

 

在狀態改變時,調用refreshDrawableState()刷新狀態。

 

最后,我們要重寫drawableStateChanged()方法,獲取到當前狀態的drawable,然后繪制出來。

 

    @Override

    protected void drawableStateChanged() {

        super.drawableStateChanged();

        if (stateListDrawable != null) {

            int[] myDrawableState = getDrawableState();

            stateListDrawable.setState(myDrawableState);

            Drawable drawable = stateListDrawable.getCurrent();

            if(drawableHeight != 0) {

                drawable.setBounds(0, 0, drawable.getIntrinsicWidth() * drawableHeight / drawable.getIntrinsicHeight(), drawableHeight);

            } else {

                drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());

            }

            if (isChecked) {

                setCompoundDrawables(drawable, null, null, null);

            } else {

                setCompoundDrawables(null, null, drawable, null);

            }

        }

        setText(isChecked ? onText : offText);

    }

 

這部分代碼中我需要設定drawable的大小,以及在不同的狀態下設置drawable的位置,因此稍微比較復雜一點點,實際上邏輯只需要如下:

 

獲取當前的drawableState狀態

對stateListDrawable(帶狀態的drawable集)設置狀態。

獲取stateListDrawable的當前狀態的drawable

進行你所想要的繪制。

這樣就完成了。

 

總結

 

從上面可知,增加狀態的過程如下:

 

定義狀態數組

重寫protected int[] onCreateDrawableState(int extraSpace)

調用refreshDrawableState()

重寫protected void drawableStateChanged()

 

以上就是android自定義控件增加狀態的方法,如果你還有更好的實現方法,歡迎補充分享。

 

相關文章:《如何實現自己的Android MVP框架?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM