天天看點

Android之selector自定義背景實作2

Android之selector自定義背景實作2

文章連結:Android之selector自定義背景實作2

文章連結:Android之selector自定義背景實作1

知識點

  1. selector和shap節點屬性詳解;
  2. selector背景/點選回報效果的XML檔案實作;
  3. selector背景/點選回報效果的Java代碼實作;
  4. 新名詞記錄{StateListDrawable:和XML設定selector相同效果的代理類;GradientDrawable:設定按鈕/控件背景的圓角/邊框等的實作類;}

書接上一回 上一回

第二種:Java代碼實作

利用第一種實作方式,我們看到要寫3個的XML檔案。但是,我懶,不想寫這麼多的檔案,應該怎麼辦呢???

很多人就會想到,我利用Java代碼來替代啊。

這個是木有問題的,因為在今天的工作中,我自己也是懶了,是以我要“另辟蹊徑”,決定用Java代碼來實作。就可以不用建立n多個資源檔案了,有時候看到這麼多檔案都煩都怕。

首先我們應該知道Google的SDK是用哪幾個類來替代XML實作的效果的。回想一下,XML代碼是被設定到background屬性去的,在Java代碼中有setBackground()方法,形參是一個Drawable,那麼我們要找到這個類,估計和Drawable類多少有些關聯的。

查一下API,果然找到了一個類:StateListDrawable。類的說明是:讓你在一個drawable上面設定一系列圖形,用以根據資源id來置換不同圖形的一個類。這個類裡面有增加狀态、動态加載一個XML檔案、擷取狀态的總數、根據下标得到狀态的drawable、應用theme等公共方法。

好啦,找到了,我們就可以開始用代碼來替代第一種方法了。這裡我使用純顔色背景來響應不同的點選回報效果。下面的方法是根據傳入的顔色的ID來擷取到一個drawable,然後傳回StateListDrawable執行個體。

/**
     * @param context      上下文
     * @param normalResId  預設的顔色
     * @param pressedResId 按下不放的顔色
     * @param strokeWidth  控件邊框的顔色
     * @param roundRadius  控件圓角的大小
     * @return drawable對象,設定了selector的效果
     */
    public StateListDrawable getPressedSelector(Context context, int normalResId, int pressedResId,
                                                int strokeWidth, int roundRadius) {
        //這裡我使用getDrawable()擷取一個drawable
        Drawable normal = normalResId == - ? null : context.getResources().getDrawable(normalResId);
        Drawable pressed = pressedResId == - ? null : context.getResources().getDrawable(pressedResId);

        StateListDrawable stateListDrawable = new StateListDrawable();
        //以下的順序很重要,normal必須在最後面才起作用
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressed);
        stateListDrawable.addState(new int[]{}, normal);

        return stateListDrawable;
    }
           

說明:這裡需要注意:我傳入一個顔色的id,使用getDrawable()擷取一個drawable在這裡是可行的。然後我們調用stateListDrawable.addState()方法來加入需要的狀态對應的圖檔。

public void addState(int[] stateSet, Drawable drawable){}
           

看到此方法,參數1是對應的狀态的int數組,可以一次傳入多個狀态,參數2是參數1所有的狀态時要展示的drawable。關于每個狀态,在第一種方法裡面已經有說明了,他們在系統android.R.attr檔案下面都有定義。這裡需要注意一點:加的時候,預設的狀态要在最後面,否則不起作用。

還有一點更加

然後我們就得到stateListDrawable執行個體,然後調用setBackground()方法将drawable設定進去,運作就可以看到效果了。

這裡我就不給出效果圖了,大家可以自己去運作看下。

你以為這就完了嗎?No No No

還有一個效果木有實作,那就是加入圓角、邊框等的效果。

我們繼續來找用來替代shap的Java類,然後我們看到這個類:GradientDrawable。GradientDrawable類說明:為按鈕和背景等提供顔色漸變的drawable。它也是一個drawable的一個直接子類。Google也說明了,這個類的功能也是可以再XML裡面利用shap來實作的。類裡面的方法,和XML裡面每個屬性功能都是有對應的,有需要深入了解的可以去看源碼。

找到了,我們就開始使用起來了。因為它是drawable的子類,那麼就可以像stateListDrawable一樣來操作,隻是方法不同罷了。使用無非就是設定它的填充顔色,圓角的角度,邊框顔色和大小等等。我們直接看代碼吧。

/**
     * @param context      上下文
     * @param normalResId  預設的顔色
     * @param pressedResId 按下不放的顔色
     * @param strokeWidth  控件邊框的顔色
     * @param roundRadius  控件圓角的大小
     * @return drawable對象,設定了selector的效果
     */
    public StateListDrawable getPressedSelector(Context context, int normalResId, int pressedResId,
                                                int strokeWidth, int roundRadius) {
        int normalFillColor = context.getResources().getColor(normalResId);
        GradientDrawable normalGd = new GradientDrawable();
        normalGd.setColor(normalFillColor);
        normalGd.setCornerRadius(roundRadius);
        normalGd.setStroke(strokeWidth, normalFillColor);

        int pressedFillColor = context.getResources().getColor(pressedResId);
        GradientDrawable pressedGd = new GradientDrawable();
        pressedGd.setColor(pressedFillColor);
        pressedGd.setCornerRadius(roundRadius);
        pressedGd.setStroke(strokeWidth, pressedFillColor);

        StateListDrawable stateListDrawable = new StateListDrawable();
        //以下的順序很重要,normal必須在最後面才起作用
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedGd);
        stateListDrawable.addState(new int[]{}, normalGd);

        return stateListDrawable;
    }
           

因為要複用,我寫了一個方法,把需要的幾個參數統一由外面傳進來。注意:我這裡傳入的還是color的資源id。如果是傳入drawable的資源,必須要使用getDrawable()方法。

調用方法:

第二種實作方法完。

總結

其實兩種方法實作起來也不難,來做一下對比:

方法一:

在XML裡面能夠看到效果,但是需要的檔案很多,管理就難了。想像一下,如果一個APP裡面有十多個不同的樣式背景或者點選回報效果,那麼檔案可能就多了幾十個了,要改變的時候得要一個一個去找,修改和管理起來比較困難。

方法二:

要運作時才能看到效果,調試比較費勁。但是代碼簡潔了不少,像我提取成一個方法,顔色等樣式由外面提供,複用性比較高,XML檔案數量幾乎為0.

OK,以上就是所有内容。

如有任何疑問,請及時與我聯系。謝謝!