在Android中,很多时候系统原生的控件的格式并不能满足我们的需求,我们想要更加好看点的样式,像什么圆角矩形啊,颜色渐变啊,阴影效果啊等等的,这个时候就是我们的ShapeDrawable发挥效果的时候了。
首先,我们要在res/drawable/ 路径下创建一个xml文件, 其格式如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners android:radius="integer" android:topLeftRadius="integer" android:topRightRadius="integer" android:bottomLeftRadius="integer" android:bottomRightRadius="integer" />
<gradient android:angle="integer" android:centerX="integer" android:centerY="integer" android:centerColor="integer" android:endColor="color" android:gradientRadius="integer" 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" />
<stroke android:width="integer" android:color="color" android:dashWidth="integer" android:dashGap="integer" />
</shape>
shape(形状)
表示绘制的形状,有四个值供选择
ring(环)
前面几种比较简单,现在就说说最后的ring(环)吧,我们必须把android:useLevel设为false,不然的话,这个环是显示不出来的。
关于Ring还有几个其特有的属性:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="ring" android:innerRadiusRatio="3" android:thicknessRatio="9" android:useLevel="false">
<solid android:color="#FF0000" />
</shape>
corners(角半径)
表示的是矩形的四个角的半径(xxdp),只能用在android:shape=”rectangle” 的时候,一般情况下就是用来实现圆角矩形的效果,它只有5个子元素,如下:
注:如果同时定义了radius和topLeftRadius,这时radius对其他角仍有效, 而topLeftRadius会覆盖radius定义左上角。
padding(内边距)
padding支持四个属性,分别是left,right,top 和 bottom。
当drawable里面有内容时(譬如它作为TextView的background),可以设置内容距离边缘的内边距,其实就跟我们平常认识的padding一样效果。
size(大小)
size支持两个属性,width和height,顾名思义就是设置drawable的大小。
solid(填充)
solid只有一个属性,就是填充的颜色color。
stroke(边缘)
stroke其实就是边缘的意思,当我们在定义画笔的时候,有很多时候会用到 FILL 和 STROKE,前者能够画出一个实心的形状,而后者就画出一个空心的图形,所以在这里,stroke表示同样的意思,就是描边。
它只有四个属性:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<stroke android:dashGap="2dp" android:dashWidth="10dp" android:width="2dp" android:color="#FF0000" />
</shape>
- gradient(渐变)
它的元素比较多,我们逐一看一下,如下:
- android:startColor(渐变起始颜色)
- android:endColor(渐变终止颜色)
- android:centerColor(渐变中间颜色)
- android:angle(渐变方向逆时针旋转的角度,必须是45的倍数,否则会报错)
- android:centerX(中间的颜色相对的位置,X就只对左右的渐变有用,0~1.0)
- android:centerY(中间的颜色相对的位置,Y就只对上下的渐变有用,0~1.0)
- android:gradientRadius(raidal渐变半径)
- android:type(渐变类型,有”linear”、”radial”和”sweep”)
下面我们通过几个例子来看一下效果:
1.两种颜色线性渐变,角度分别为0、45、90、180
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="15dip"/>
<gradient android:startColor="#FF0000" android:endColor="#00FF00" android:angle="45" android:type="linear"/>
</shape>
可以看到,从0到180,渐变颜色会慢慢随着逆时针的方向旋转。而这个角度的值必须是45的倍数,否则会报错。不过我们仔细看一下,其实方向只有上下左右,45和0其实没有区别。
2.三种颜色线性渐变,centerX分别为0.2、0.4、0.6、0.8
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="15dip"/>
<gradient android:startColor="#FF0000" android:centerColor="#0000FF" android:endColor="#00FF00" android:centerX="0.2" android:type="linear"/>
</shape>
可以看到渐变开始部分从水平方向逐渐右移,同理centerY控制竖直方向的渐变点。我们不写这两个属性,默认值都是0.5,从中间开始。
3.两种颜色辐射渐变,渐变半径分别为100、200、300、400
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<gradient android:startColor="#FF0000" android:endColor="#00FF00" android:gradientRadius="100" android:type="radial"/>
</shape>
可以看到渐变半径逐渐增大,当android:type=”raidal”的时候,gradientRadius的属性是一定要设置的。
4.三种颜色扫描渐变,centerX分别为0.1、0.5、0.9,同时centerY也为0.1、0.5、0.9
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="15dip"/>
<gradient android:startColor="#FF0000" android:centerColor="#0000FF" android:centerX="0.1" android:centerY="0.1" android:endColor="#00FF00" android:type="sweep"/>
</shape>
在type=”sweep”中,angle的属性是一点用没有的,而centerX/Y跟radial一样,都是针对开始颜色的比例来设置的,x是针对开始颜色在X轴上面的比例,而y则是针对在Y轴上面的比例。
Android中的Selector是背景选择器,主要是用来改变ListView和Button控件的默认背景。Selector状态相关属性:
android:state_selected是选中
android:state_focused是获得焦点
android:state_pressed是点击
android:state_enabled是设置是否响应事件,指所有事件
其使用方法可以按以下步骤来设计:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 没有焦点时的背景图片 -->
<item android:drawable="@drawable/pic_1" android:state_window_focused="false"/>
<!-- 非触摸模式下获得焦点并单击时的背景图片 -->
<item android:drawable="@drawable/pic_2" android:state_focused="true" android:state_pressed="true"/>
<!-- 触摸模式下单击时的背景图片 -->
<item android:drawable="@drawable/pic_3" android:state_focused="false" android:state_pressed="true"/>
<!-- 选中时的图片背景 -->
<item android:drawable="@drawable/pic_4" android:state_selected="true"/>
<!-- 获得焦点时的图片背景 -->
<item android:drawable="@drawable/pic_5" android:state_focused="true"/>
<!-- 默认时的背景图片 -->
<item android:drawable="@drawable/pic_1"/>
</selector>
其实我们很少会在一个xml中用到这么多状态,最常见的是在正常状态下显示一个drawable,在按下状态显示另一个drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/alarm_add_btn" android:state_pressed="false" ></item>
<item android:drawable="@drawable/alarm_add_btn_selected" android:state_pressed="true" ></item>
</selector>
这里的drawable也可以是color,这样就变成:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@color/blue_bg" android:state_pressed="true"></item>
<item android:drawable="@color/white_bg" android:state_pressed="false"></item>
</selector>
注:对seletor文件的解析是按照xml中item的先后顺序来的,即第一个item满足条件就显示第一个,不再往下找,不满足再找第二个,以此类推。
(1)ListView中使用
方法一:在ListView中添加如下属性代码
android:listSelector="@drawable/my_listview"
方法二:在ListView的item界面中添加如下属性代码
android:background="@drawable/my_listview"
方法三:在JAVA代码中直接编写
Drawable drawable = getResources().getDrawable(R.drawable.my_listview);
listView.setSelector(drawable);
注:但是这样会出现列表有时候为黑的情况,所以需要在ListView中添加以下的属性代码使其透明
android:cacheColorHint="@android:color/transparent";
(2)Button中使用
根据这些状态同样可以设置button的selector效果。还可以设置selector改变button中的文字状态。以下是配置button中的文字颜色效果:drawable/button_font.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#FFF" />
<item android:state_focused="true" android:color="#FFF" />
<item android:state_pressed="true" android:color="#FFF" />
<item android:color="#000" />
</selector>
selector关联到控件:
<Button
android:id="@+id/button"
android:layout_width="200dp"
android:layout_height="100dp"
android:focusable="true"
android:text="Button"
android:textColor="@drawable/button_font"/>
Button还可以实现更复杂的效果,例如渐变:drawable/button_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<gradient android:startColor="#8600ff" />
<stroke android:width="2dp" android:color="#000000" />
<corners android:radius="5dp" />
<padding android:left="10dp" android:top="10dp" android:bottom="10dp" android:right="10dp"/>
</shape>
</item>
<item android:state_pressed="false">
<shape>
<gradient android:startColor="#eac100"/>
<stroke android:width="2dp" android:color="#333333"/>
<corners android:radius="8dp" />
<padding android:left="10dp" android:top="10dp" android:bottom="10dp" android:right="10dp"/>
</shape>
</item>
</selector>
selector关联到控件:
<Button
android:id="@+id/button"
android:layout_width="200dp"
android:layout_height="100dp"
android:focusable="true"
android:text="Button"
android:background="@drawable/button_color"/>
Android layer-list是用来做多个图层(item)堆叠显示的,借这个特性可以做一些特别的效果(比如:阴影、下面的效果等)。
每个item都可以有自己的属性:
1.先来看一个简单的例子
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:src="@drawable/android_red" android:gravity="center" />
</item>
<item android:top="10dp" android:left="10dp">
<bitmap android:src="@drawable/android_green" android:gravity="center" />
</item>
<item android:top="20dp" android:left="20dp">
<bitmap android:src="@drawable/android_blue" android:gravity="center" />
</item>
</layer-list>
<ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/layers" />
2.通过layer-list多图层叠加效果实现圆角功能, 效果如下图所示
四个角都是圆角的效果。如果让UI设计人员直接出图,可能会更简单一些。但是我们使用android中layer-list多图层叠加效果同样可以实现。
我们把它拆分为三个部分,第一个部分是最顶端的那一行(我这里称为顶部),第二部分是中间部分(中间部分不需要圆角效果),第三部分是底部。
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<shape>
<solid android:color="#FFFFFF" />
<corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomRightRadius="0.1dp" android:bottomLeftRadius="0.1dp" />
<stroke android:width="1dp" android:color="#ffa8abad" />
</shape>
</item>
<item android:top="1dp" android:left="1dp" android:right="1dp">
<shape>
<solid android:color="#FFFFFF" />
<corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomRightRadius="0.1dp" android:bottomLeftRadius="0.1dp" />
</shape>
</item>
</layer-list>
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape>
<solid android:color="#FFFFFF" />
<stroke android:width="1dp" android:color="#ffa8abad" />
</shape>
</item>
<item android:left="1dp" android:right="1dp" android:top="1dp">
<shape>
<solid android:color="#FFFFFF" />
</shape>
</item>
</layer-list>
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#FFFFFF" />
<corners android:topLeftRadius="0.1dp" android:topRightRadius="0.1dp" android:bottomRightRadius="10dp" android:bottomLeftRadius="10dp" />
<stroke android:width="1dp" android:color="#ffa8abad" />
</shape>
</item>
</layer-list>
使用layer-list图片
...
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:orientation="vertical" >
<TextView
android:id="@+id/text1"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@drawable/subscribe_bg"
android:gravity="center"
android:text="Text1" />
<TextView
android:id="@+id/text2"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@drawable/subscribe_bg2"
android:gravity="center"
android:text="Text2" />
<TextView
android:id="@+id/text2"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@drawable/subscribe_bg3"
android:gravity="center"
android:text="Text3" />
</LinearLayout>
我们将上中下部分分别拆分开来和并在一起,显示效果如下:
在本文最后将结合上面学习过的三个内容, 做水平一个导航栏,点击后会切换不同选项,大概是下面这种效果:
我们将它拆分:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="#FF545A" />
<corners android:bottomLeftRadius="20dp" android:bottomRightRadius="0.1dp" android:topLeftRadius="20dp" android:topRightRadius="0.1dp" />
</shape>
</item>
<item android:state_selected="false">
<layer-list>
<item>
<shape android:shape="rectangle" >
<solid android:color="#ECECEC" />
<stroke android:width="1dp" android:color="#FF545A" />
<corners android:bottomLeftRadius="20dp" android:bottomRightRadius="0.1dp" android:topLeftRadius="20dp" android:topRightRadius="0.1dp" />
</shape>
</item>
<item android:left="1dp" android:bottom="1dp" android:top="1dp">
<shape android:shape="rectangle" >
<solid android:color="#ECECEC" />
<corners android:bottomLeftRadius="20dp" android:bottomRightRadius="0.1dp" android:topLeftRadius="20dp" android:topRightRadius="0.1dp" />
</shape>
</item>
</layer-list>
</item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="#FF545A" />
<corners android:bottomLeftRadius="0.1dp" android:bottomRightRadius="20dp" android:topLeftRadius="0.1dp" android:topRightRadius="20dp" />
</shape>
</item>
<item android:state_selected="false">
<layer-list>
<item>
<shape android:shape="rectangle" >
<solid android:color="#ECECEC" />
<stroke android:width="1dp" android:color="#FF545A" />
<corners android:bottomLeftRadius="0.1dp" android:bottomRightRadius="20dp" android:topLeftRadius="0.1dp" android:topRightRadius="20dp" />
</shape>
</item>
<item android:right="1dp" android:bottom="1dp" android:top="1dp">
<shape android:shape="rectangle" >
<solid android:color="#ECECEC" />
<corners android:bottomLeftRadius="0.1dp" android:bottomRightRadius="20dp" android:topLeftRadius="0.1dp" android:topRightRadius="20dp" />
</shape>
</item>
</layer-list>
</item>
</selector>
把图片关联到TextView背景
<LinearLayout android:layout_width="200dp" android:layout_height="40dp" android:layout_gravity="center_horizontal" android:layout_marginTop="20dp" android:orientation="horizontal" >
<TextView android:id="@+id/news_blog" android:layout_width="0dp" android:layout_height="35dp" android:layout_weight="1" android:background="@drawable/left_filter_bg" android:gravity="center" android:text="最新博客" android:textColor="#ffffff" android:textSize="18sp" />
<TextView android:id="@+id/hots_blog" android:layout_width="0dp" android:layout_height="35dp" android:layout_weight="1" android:layout_marginLeft="10dp" android:background="@drawable/right_filter_bg" android:gravity="center" android:text="热门博客" android:textColor="#FF545A" android:textSize="18sp" />
</LinearLayout>
当我们点击TextView时还要控制TextView的字体颜色以及它的selected状态:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
newblog = (TextView) findViewById(R.id.news_blog);
hotblog = (TextView) findViewById(R.id.hots_blog);
seletedNewBlog();
newblog.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
seletedNewBlog();
}
});
hotblog.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
seletedHotBlog();
}
});
}
private void seletedNewBlog (){
newblog.setSelected(true);
newblog.setTextColor(Color.parseColor("#ffffff"));
hotblog.setSelected(false);
hotblog.setTextColor(Color.parseColor("#FF545A"));
}
private void seletedHotBlog (){
hotblog.setSelected(true);
hotblog.setTextColor(Color.parseColor("#ffffff"));
newblog.setSelected(false);
newblog.setTextColor(Color.parseColor("#FF545A"));
}
注:Java代码中设置颜色几种方式:
setTextColor(0xffffffff); //0xFF0000FF是int类型的数据,必须是8个的颜色表示,不接受0000FF这种6个的颜色表示
setTextColor(Color.parseColor("#ffffff"));
setTextColor(this.getResources().getColor(R.color.blue));//通过获得资源文件进行设置
setTextColor(Android.graphics.Color.BLUE); //使用系统自带的颜色类
看一下运行效果吧:
Demo下载地址