selector,shape,layer-list

selector

选择器;可使控件在不同操作下(点击,选中等),显示不同的样式。

xml属性 说明
android:drawable 放一个drawable资源,一般为图片,颜色或者是shape图形。
android:state_selected 选中状态(最常用的属性)
android:state_checked 勾选状态(常用与RadioButton或CheckBox)
android:state_pressed 按下状态(如按钮按下,但还没松手)
android:state_enabled 是否可用(如按钮是否可以点击)
android:state_focused 取得焦点状态,比如用户选择了一个文本框。
android:state_hovered 光标悬停状态,它是4.0的新特性。

示例:
selector_use.xml文件(res->drawable目录下):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<!--常用的选择器-->

<!--选中-->
<!--drawable资源为颜色。true为自定义的颜色,false为系统的颜色-->
<item android:state_selected="true" android:drawable="@color/red" />
<item android:state_selected="false" android:drawable="@android:color/holo_blue_light" />

<!--是否可用-->
<!--drawable资源为图片。true显示方形的机器人图标,false显示圆形的机器人图标-->
<item android:state_enabled="true" android:drawable="@drawable/ic_launcher" />
<item android:state_enabled="false" android:drawable="@drawable/ic_launcher_round" />

<!--点击状态-->
<!--drawable资源为shape图形。true显示方形,false为圆形。-->
<item android:state_pressed="true" android:drawable="@drawable/shape_rectangle" />
<item android:state_pressed="false" android:drawable="@drawable/shape_circle" />

<!--勾选状态-->
<!--drawable资源为图片。true显示方形的机器人图标,false显示圆形的机器人图标。-->
<!--一般用于同意协议,将图片换成UI给的图就可以。-->
<item android:state_checked="true" android:drawable="@drawable/ic_launcher" />
<item android:state_checked="false" android:drawable="@drawable/ic_launcher_round" />

</selector>

activity_main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!--按钮我习惯使用TextView-->
<!--选中状态-->
<TextView
android:id="@+id/tv_selector"
android:background="@drawable/selector_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="selector"
android:textColor="@android:color/white"/>

<!--按钮是否可用-->
<Button
android:id="@+id/btn_enabled"
android:background="@drawable/selector_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="enabled"
android:textColor="@android:color/white"/>

<!--点击状态-->
<TextView
android:id="@+id/tv_pressed"
android:clickable="true"
android:background="@drawable/selector_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="pressed"
/>

<!--勾选状态-->
<!--效果一般用于同意协议-->
<LinearLayout
android:id="@+id/ll_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/cb_checked"
android:button="@null"
android:background="@drawable/selector_use"
android:layout_width="20dp"
android:layout_height="20dp"
/>
<TextView
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="checked"/>
</LinearLayout>

MainActivity.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 选中状态
final TextView tvSelector = findViewById(R.id.tv_selector);
tvSelector.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (tvSelector.isSelected()){
tvSelector.setSelected(false);
}else {
tvSelector.setSelected(true);
}
}
});
// 可用状态
final Button btnEnabled = findViewById(R.id.btn_enabled);
btnEnabled.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (btnEnabled.isEnabled()){
btnEnabled.setEnabled(false);
btnEnabled.postDelayed(new Runnable() {
@Override
public void run() {
btnEnabled.setEnabled(true);
}
},3000);
}
}
});
// 点击状态
final TextView tvPressed = findViewById(R.id.tv_pressed);

// 勾选状态
LinearLayout llChecked = findViewById(R.id.ll_checked);
final CheckBox checkBox = findViewById(R.id.cb_checked);
llChecked.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (checkBox.isChecked()){
checkBox.setChecked(false);
}else {
checkBox.setChecked(true);
}
}
});

shape

主要设置布局的形状,填充色,边框等属性。可以用来当控件背景,或者选择器的drawable资源等。
相较于图片,体积更小,适配性也更好。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<!--shape可以指定的四种图形-->
<!--分别是;矩形(rectangle)、椭圆(oval)、线(line)、圆环(ring)。-->

<!--当类型是圆环时(android:shape="ring");还会多出几个属性。-->
<!--android:innerRadius="dimension" 内环半径-->
<!--android:innerRadiusRatio="float" 内环半径相对于环的宽度的比例,比如环的宽度为50,比例为2.5,那么内环半径为20-->
<!--android:thickness="dimension" 环的厚度-->
<!--android:thicknessRatio="float" 环的厚度相对于环的宽度的比例-->
<!--android:useLevel="boolean" 如果当做是LevelListDrawable使用时值为true,否则为false.-->

<!--定义圆角-->
<corners
android:radius="integer" // 四个角的圆角大小。
android:topLeftRadius="integer" // 单独设置一个角,左上角的圆角大小。
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />

<!--定义渐变效果-->
<!--type;渐变类型;-->
<!--linear 线性渐变,默认的渐变类型-->
<!--radial 放射渐变,设置该项时,android:gradientRadius也必须设置-->
<!--sweep 扫描性渐变-->
<gradient
android:angle="integer" // 渐变角度(必须是45的倍数):0:左到右;90:下到上;180:右到左;270:上到下
android:centerX="integer" // 表示渐变的X轴起始位置,范围0-10.5表示圆心。
android:centerY="integer" // 表示渐变的Y轴起始位置,范围0-10.5表示圆心。
android:centerColor="integer" // 渐变中间点的颜色,在开始与结束点之间
android:endColor="color" // 渐变的结束颜色
android:gradientRadius="integer" // 渐变的半径,只有当渐变类型为radial时才能使用
android:startColor="color" // 渐变的起始颜色
android:type=["linear" | "radial" | "sweep"]
android:useLevel=["true" | "false"] />

<!--内边距-->
<padding
android:left="integer"
android:top="integer"
android:right="integer"
android:bottom="integer" />

<!--自定义的图形大小-->
<size
android:width="integer"
android:height="integer" />

<!--内部填充色-->
<solid
android:color="color" />

<!--边框(描边)-->
<!--dashWidth 虚线宽度,值为0时是实线。-->
<!--dashGap 虚线间距宽度,虚线的间隔。-->
<stroke
android:width="integer" // 边框线宽度
android:color="color" // 边框颜色
android:dashWidth="integer"
android:dashGap="integer" />

</shape>

效果:

图例:

线性圆角矩形
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:width="40dp" android:height="40dp" />
<corners android:radius="20dp" />
<gradient android:startColor="@color/colorAccent" android:endColor="@color/colorPrimary"
android:type="linear" android:angle="90"/>
</shape>

注:对于一些简单的效果,比如是否有边框,填充的颜色等,可以使用GradientDrawable来实现。
但要注意,属性会继承下去。也就是说,在使用了shape_use.xml资源的地方,没有设置GradientDrawable,会默认显示上一次设置的效果。

activity_main.xml
1
2
3
4
5
6
7
8
<TextView
android:layout_gravity="center"
android:id="@+id/tv_shape_use"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center"
android:textColor="@android:color/white"
android:text="shape"/>
shape_use.xml
1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

</shape>
动态改变shape
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 动态改变shape
*/
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.tv_shape_use);
// 先设置背景
tv.setBackgroundResource(R.drawable.shape_use);
GradientDrawable gradientDrawable = (GradientDrawable) tv.getBackground();
// 设置shape类型,这里是矩形
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
// 圆角角度
gradientDrawable.setCornerRadius(dp2px(this,20));
// 填充色
gradientDrawable.setColor(getResources().getColor(R.color.colorAccent));
// 边框
gradientDrawable.setStroke(dp2px(this,1),getResources().getColor(R.color.colorPrimary));

}

//dp转px;
public static int dp2px(Context mContext, int dp){
return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5);
}
}

layer-list

可以通过item把图层按顺序叠起来,实现一些特殊的效果。
layer-list中的item标签可以通过下面四个属性设置偏移量:

  • android:top 顶部的偏移量
  • android:bottom 底部的偏移量
  • android:left 左边的偏移量
  • android:right 右边的偏移量
  • 这四个偏移量和控件的margin设置差不多,都是外间距的效果。

图例:

Table选项卡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<!-- 红色背景 -->
<item>
<color android:color="#E4007F" />
</item>
<!-- 白色背景 -->
<item android:bottom="4dp" android:drawable="@android:color/white" />
</layer-list>
</item>
<item>
<layer-list>
<!-- 红色背景 -->
<item>
<color android:color="#E4007F" />
</item>
<!-- 白色背景 -->
<item android:drawable="@android:color/white" />
</layer-list>
</item>
</selector>
渐变边框
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--边框阴影-->
<!--当没有UI图时,将颜色换成渐变的,可以实现类似的边框渐变阴影的效果来凑合用。-->
<!--最外层-->
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners android:radius="4dp" />
</shape>
</item>
<item android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/colorPrimary" />
<corners android:radius="4dp" />
</shape>
</item>
<!--最内层-->
<item android:bottom="3dp" android:left="3dp" android:right="3dp" android:top="3dp">
<shape android:shape="rectangle">
<solid android:color="@color/colorPrimaryDark" />
<corners android:radius="4dp" />
</shape>
</item>
<!--内容区-->
<item android:bottom="4dp" android:left="4dp" android:right="4dp" android:top="4dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="4dp" />
</shape>
</item>

</layer-list>

链接

传送门GitHub