[原創]android使用代碼生成LayerDrawable的方法和注意事項

爲了有更好的UI體驗,通常咱們會把button、textview等控件的背景設置上陰影。傳統的作法是美工提供一張具備陰影效果的nine patch圖,而後將其在xml文件中添加到background屬性。這種作法沒有問題,不過缺少靈活性。java

圖1.使用代碼生成的具備「陰影」效果的控件android

在android中,每一種在xml文件中定義的圖片,都可以使用java代碼生成,其中LayerDrawable對應的xml文件的根元素爲<layer-list>。ide

首先我介紹一下使用xml文件生成「陰影」背景效果圖片:函數

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

    <item >
        <shape android:shape="rectangle" >
            <solid android:color="#ffbbbbbb" />

            <corners android:radius="2dp" />

        </shape>
    </item >

    <item
        android:bottom="1px"
        android:right="1px" >
        <shape android:shape="rectangle" >
            <solid android:color="#ffdddddd" />

            <corners android:radius="2dp" />

            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp" />
        </shape>
    </item >

</layer-list>

解析:this

1.shape元素生成ShapeDrawable對象,不過須要注意的是,xml中雖然指明生成"rectangle"類型的對象,但若是想要在java中生成的rectangle具備圓角,那麼java中對應的shape應該是RoundRectShape。
2.solid元素指明背景顏色,且paint的style爲fill。
3.第二個元素android:bottom等表明的是LayerDrawable中第二個drawable相對於第一個drawable的inset,對應的java代碼爲:
layerDrawable.setLayerInset(1, 0, 0, 1, 1);
源碼爲:
 1 /** Specify modifiers to the bounds for the drawable[index].
 2         left += l
 3         top += t;
 4         right -= r;
 5         bottom -= b;
 6     */
 7     public void setLayerInset(int index, int l, int t, int r, int b) {
 8         ChildDrawable childDrawable = mLayerState.mChildren[index];
 9         childDrawable.mInsetL = l;
10         childDrawable.mInsetT = t;
11         childDrawable.mInsetR = r;
12         childDrawable.mInsetB = b;
13     }

能夠看出setLayerInset()函數的做用就是將某層(層數從0開始計數)相對於上一層進行向裏偏移。固然若是傳入的數值爲負數,就是向外偏移了,不過這時上層就遮擋住下層了,失去了使用layer的意義了。spa

4.padding的做用一樣很是重要:3d

    (1)當在最上層使用padding時,它指明的是最上層的drawable邊緣與內容之間的padding;code

    (2)當在非最上層使用padding時,它指明當前層與上層之間的padding。

orm

 

下面使用java代碼生成LayerDrawable。xml

 

 1 private void setLayerBg(View view){
 2         
 3         int radius0 = 10;
 4         float[] outerR = new float[] { radius0, radius0, radius0, radius0, radius0, radius0, radius0, radius0 };
 5         RoundRectShape roundRectShape0 = new RoundRectShape(outerR, null, null);
 6         
 7         int radius1 = 10;
 8         float[] outerR1 = new float[] { radius1, radius1, radius1, radius1, radius1, radius1, radius1, radius1 };
 9         RoundRectShape roundRectShape1 = new RoundRectShape(outerR1, null, null);
10         
11         ShapeDrawable shapeDrawableBg = new ShapeDrawable();
12         
13         shapeDrawableBg.setPadding(0, 0, 0, 0);
14         shapeDrawableBg.setShape(roundRectShape0);
15 
16         shapeDrawableBg.getPaint().setStyle(Paint.Style.FILL);
17         shapeDrawableBg.getPaint().setColor(0xffbbbbbb);
18         
19         
20         ShapeDrawable shapeDrawableFg = new ShapeDrawable();
21         
22         shapeDrawableFg.setPadding(23, 23, 23, 23);
23         shapeDrawableFg.setShape(roundRectShape1);
24 
25         shapeDrawableFg.getPaint().setStyle(Paint.Style.FILL);
26         shapeDrawableFg.getPaint().setColor(0xffdddddd);
27         
28         Drawable[] layers = {shapeDrawableBg, shapeDrawableFg};
29         LayerDrawable layerDrawable = new LayerDrawable(layers);
30         layerDrawable.setLayerInset(1, 0, 0, 1, 1);
31         
32         view.setBackgroundDrawable(layerDrawable);
33         
34     }

註釋我就不寫了,具體的解釋見上面的解析。

 

LayerDrawable和StateListDrawable相結合使用

當咱們遇到可點擊的控件時,須要給此控件自定義幾個不一樣狀態的background,好比按下效果、普通狀態效果,這時就須要用到StateListDrawable。

採用LayerDrawable生成的圖片具備的只是靜態屬性,當將不一樣狀態的LayerDrawable添加到一個StateListDrawable中,這樣控件不一樣狀態時均選擇是否具備陰影效果。

代碼以下:

 1 @Override
 2     protected void onCreate(Bundle savedInstanceState) {
 3         super.onCreate(savedInstanceState);
 4         setContentView(R.layout.activity_main);
 5     
 6         text  = (TextView)this.findViewById(R.id.text);
 7         text.setBackgroundDrawable(getStateListDrawable());
 8         text.setOnClickListener(new View.OnClickListener() {
 9             
10             @Override
11             public void onClick(View v) {
12                 Toast.makeText(getApplicationContext(), "ttt", Toast.LENGTH_SHORT).show();
13             }
14         });
15    }
16 
17     private Drawable getStateListDrawable(){
18 
19         StateListDrawable stateListDrawable = new StateListDrawable();
20 
21         int[] stateHighlighted = new int[]{android.R.attr.state_pressed};
22         Drawable highlightedDrawable = getLayerDrawable(0xffcccccc);
23         stateListDrawable.addState(stateHighlighted, highlightedDrawable);
24 
25         int[] stateNormal = new int[]{};
26         Drawable normalDrawable = getLayerDrawable(0xffdddddd);
27         stateListDrawable.addState(stateNormal, normalDrawable);
28 
29         return stateListDrawable;
30     }
31     
32     private Drawable getLayerDrawable(int foregroundColor){
33         
34         int radius0 = 10;
35         float[] outerR = new float[] { radius0, radius0, radius0, radius0, radius0, radius0, radius0, radius0 };
36         RoundRectShape roundRectShape0 = new RoundRectShape(outerR, null, null);
37         
38         int radius1 = 10;
39         float[] outerR1 = new float[] { radius1, radius1, radius1, radius1, radius1, radius1, radius1, radius1 };
40         RoundRectShape roundRectShape1 = new RoundRectShape(outerR1, null, null);
41         
42         ShapeDrawable shapeDrawableBg = new ShapeDrawable();
43         shapeDrawableBg.setPadding(0, 0, 0, 0);
44         shapeDrawableBg.setShape(roundRectShape0);
45         shapeDrawableBg.getPaint().setStyle(Paint.Style.FILL);
46         shapeDrawableBg.getPaint().setColor(0xffbbbbbb);
47         
48         ShapeDrawable shapeDrawableFg = new ShapeDrawable();
49         shapeDrawableFg.setPadding(23, 23, 23, 23);
50         shapeDrawableFg.setShape(roundRectShape1);
51         shapeDrawableFg.getPaint().setStyle(Paint.Style.FILL);
52         shapeDrawableFg.getPaint().setColor(foregroundColor);
53         
54         Drawable[] layers = {shapeDrawableBg, shapeDrawableFg};
55         LayerDrawable layerDrawable = new LayerDrawable(layers);
56         layerDrawable.setLayerInset(1, 0, 0, 1, 1);
57         
58         return layerDrawable;
59     }

 

須要注意的是:當給View、TextView、ImageView、ViewGroup等類型的默認沒有按下事件的控件添加StateListDrawable時,控件須要設置上click事件,不然按下效果不起做用

備註:

這裏只是經過兩幅顏色單一的drawable錯位簡單的生成「陰影效果」,後續能夠經過shader等效果,生成逐漸淡出的「陰影」效果。

 

使用xml定義layer-list的示例:

 

使用layer-list定義的xml做爲button的背景。其中:

Button1:
1.底部drawable沒有設置padding
2.頂部drawable沒有設置padding
3.頂部drawable設置inset爲5px

        android:left="5px"
        android:top="5px"
        android:bottom="5px"
        android:right="5px"

button1背景的完整xml:

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

    <item >
        <shape android:shape="rectangle" >
            <solid android:color="#ff00ff00" />

            <corners android:radius="3dp" />
            
        </shape>
    </item >

    <item
        android:left="5px"
        android:top="5px"
        android:bottom="5px"
        android:right="5px" >
        <shape android:shape="rectangle" >
            <solid android:color="#ffff0000" />

            <corners android:radius="3dp" />

        </shape>
    </item >

</layer-list>    

 

Button2:
1.底部drawable沒有設置padding
2.頂部drawable設置inset均爲5px

        android:left="5px"
        android:top="5px"
        android:bottom="5px"
        android:right="5px"

3.頂部drawable設置padding均爲50dp

     <padding
            android:bottom="50dp"
            android:left="50dp"
            android:right="50dp"
            android:top="50dp" />

 

button2背景的完整xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- Z-Order 底部drawable -->
    <item >
        <shape android:shape="rectangle" >
            <solid android:color="#ff00ff00" />

            <corners android:radius="3dp" />
            
        </shape>
    </item >

    <!-- 頂部drawable -->
    <item
        android:left="5px"
        android:top="5px"
        android:bottom="5px"
        android:right="5px" >
        <shape android:shape="rectangle" >
            <solid android:color="#ffff0000" />

            <corners android:radius="3dp" />

            <padding
                android:bottom="50dp"
                android:left="50dp"
                android:right="50dp"
                android:top="50dp" />
        </shape>
    </item >

</layer-list>

 

Button3:
1.底部drawable設置padding均爲20dp
2.頂部drawable沒有設置inset
3.頂部drawable設置padding均爲50dp

 

    <padding
            android:bottom="50dp"
            android:left="50dp"
            android:right="50dp"
            android:top="50dp" />

 

button3背景的完整xml:

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

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#ff00ff00" />

            <corners android:radius="3dp" />

            <padding
                android:bottom="20dp"
                android:left="20dp"
                android:right="20dp"
                android:top="20dp" />
        </shape>
    </item>

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#ffff0000" />

            <corners android:radius="3dp" />

            <padding
                android:bottom="50dp"
                android:left="50dp"
                android:right="50dp"
                android:top="50dp" />
        </shape>
    </item>

</layer-list>    
相關文章
相關標籤/搜索