当然除了使用drawable这样的图片外今天谈下自定义图形shape的方法,对于button控件android上支持以下几种属性shape、gradient、stroke、corners等。
我们就以目前系统的button的selector为例说下:
<shape> <gradient android:startcolor="#ff8c00" android:endcolor="#ffffff" android:angle="270" /> <stroke android:width="2dp" android:color="#dcdcdc" /> <corners android:radius="2dp" /> <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" /> </shape>
对于上面,这条shape的定义,分别为渐变,在gradient中startcolor属性为开始的颜色,endcolor为渐变结束的颜色,下面的angle是角度。接下来是stroke可以理解为边缘,corners为拐角这里radius属性为半径,最后是相对位置属性padding。
对于一个button完整的定义可以为:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://www.norkoo.com"> <item android:state_pressed="true" > <shape> <gradient android:startcolor="#ff8c00" android:endcolor="#ffffff" android:angle="270" /> <stroke android:width="2dp" android:color="#dcdcdc" /> <corners android:radius="2dp" /> <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" /> </shape> </item> <item android:state_focused="true" > <shape> <gradient android:startcolor="#ffc2b7" android:endcolor="#ffc2b7" android:angle="270" /> <stroke android:width="2dp" android:color="#dcdcdc" /> <corners android:radius="2dp" /> <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" /> </shape> </item> <item> <shape> <gradient android:startcolor="#ff9d77" android:endcolor="#ff9d77" android:angle="270" /> <stroke android:width="2dp" android:color="#fad3cf" /> <corners android:radius="2dp" /> <padding android:left="10dp" android:top="10dp" android:right="10dp" android:bottom="10dp" /> </shape> </item> </selector>
注意!提示大家,以上几个item的区别主要是体现在state_pressed按下或state_focused获得焦点时,当当来判断显示什么类型,而没有state_xxx属性的item可以看作是常规状态下。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:color="hex_color"
android:state_pressed=["true" | "false"]
android:state_focused=["true" | "false"]
android:state_selected=["true" | "false"]
android:state_active=["true" | "false"]
android:state_checkable=["true" | "false"]
android:state_checked=["true" | "false"]
android:state_enabled=["true" | "false"]
android:state_window_focused=["true" | "false"] />
</selector>
elements:
<selector>
必须。必须是根元素。包含一个或多个<item>元素。
attributes:
xmlns:android
string,必须。定义xml的命名空间,必须是
“http://schemas.android.com/apk/res/android”.
<item>
定义特定状态的color,通过它的特性指定。必须是<selector>的子元素。
attributes:
android:color
16进制颜色。必须。这个颜色由rgb值指定,可带alpha。
这个值必须以“#”开头,后面跟随alpha-red-green-blue信息:
l #rgb
l #argb
l #rrggbb
l #aarrggbb
android:state_pressed
boolean。“true”表示按下状态使用(例如按钮按下);“false”表示非按下状态使用。
android:state_focused
boolean。“true”表示聚焦状态使用(例如使用滚动球/d-pad聚焦button);“false”表示非聚焦状态使用。
android:state_selected
boolean。“true”表示选中状态使用(例如tab打开);“false”表示非选中状态使用。
android:state_checkable
boolean。“true”表示可勾选状态时使用;“false”表示非可勾选状态使用。(只对能切换可勾选—非可勾选的构件有用。)
android:state_checked
boolean。“true”表示勾选状态使用;“false”表示非勾选状态使用。
android:state_enabled
boolean。“true”表示可用状态使用(能接收触摸/点击事件);“false”表示不可用状态使用。
android:window_focused
boolean。“true”表示应用程序窗口有焦点时使用(应用程序在前台);“false”表示无焦点时使用(例如notification栏拉下或对话框显示)。
注意:记住一点,statelist中第一个匹配当前状态的item会被使用。因此,如果第一个item没有任何状态特性的话,那么它将每次都被使用,这也是为什么默认的值必须总是在最后(如下面的例子所示)。
examples:
xml文件保存在res/color/button_text.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:color="#ffff0000"/> <!-- pressed -->
<item android:state_focused="true"
android:color="#ff0000ff"/> <!-- focused -->
<item android:color="#ff000000"/> <!-- default -->
</selector>
这个layout xml会应用colorstatelist到一个view上:
<button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/button_text"
android:textcolor="@color/button_text" />
在android上开发项目,如果仅仅是采用默认的样式可能不是很美观,需要编写响应的样式来使界面美观,在iphone上常用的圆角ListView的实现。
本人实现的原理如下:
通过重写ListView中拦截触摸的事件方式,在生成ListView时候根据不同行采用不同的样式。如第一个行,最末一行,和中建行。(特殊的情况下只有一行的时候,四个角均为圆角考虑)。
实现如下:
最后一行为时候,下方两个角为圆角样式如下:
app_list_corner_round_bottom.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#BFEEFF" android:endColor="#40B9FF" android:angle="270"/> <corners android:bottomLeftRadius="6dip" android:bottomRightRadius="6dip" /> </shape>
第一行为圆角且仅仅为一条记录使用样式:
app_list_corner_round.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#BFEEFF" android:endColor="#40B9FF" android:angle="270"/> <corners android:topLeftRadius="6dip" android:topRightRadius="6dip" android:bottomLeftRadius="6dip" android:bottomRightRadius="6dip"/> </shape>
第一行为圆角且有多条记录使用样式:
app_list_corner_round_top.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#BFEEFF" android:endColor="#40B9FF" android:angle="270"/> <corners android:topLeftRadius="6dip" android:topRightRadius="6dip"/> </shape>
多行记录非第一行和最末一行使用的样式:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#BFEEFF" android:endColor="#40B9FF" android:angle="270"/> </shape>
重写的ListView
package com.easyway.listview.corner; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.AdapterView; import android.widget.ListView; /** * 圆角ListView * 重写ListView的样式实现相关的样式 * app_list_corner_round_top.xml * <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:startColor="#BFEEFF" android:endColor="#40B9FF" android:angle="270"/> <corners android:topLeftRadius="6dip" android:topRightRadius="6dip"/> </shape> * * android:shape 配置的是图形的形式,主要包括方形、圆形等,上边代码为方形。 * gradient节点主要配置起点颜色、终点颜色、中间点的坐标、中间点的颜色、渐变角度(90度为上下渐变,0为左右渐变), * padding节点主要配置上下左右边距, * corners节点配置四周园角的半径。 * * * @Title: * @Description: 实现TODO * @Copyright:Copyright (c) 2011 * @Company:易程科技股份有限公司 * @Date:2012-7-16 * @author longgangbai * @version 1.0 */ public class CornerListView extends ListView { public CornerListView(Context context) { super(context); } public CornerListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public CornerListView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 重写此方式实现不同行的样式不一样 * */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { // case MotionEvent.ACTION_DOWN: int x = (int) ev.getX(); int y = (int) ev.getY(); //返回记录数据行数 int itemnum = pointToPosition(x, y); if (itemnum == AdapterView.INVALID_POSITION) break; else{ if(itemnum==0){ if(itemnum==(getAdapter().getCount()-1)){ setSelector(R.drawable.app_list_corner_round); //仅仅一行记录的样式 }else{ setSelector(R.drawable.app_list_corner_round_top); //多行且第一行的样式 } }else if(itemnum==(getAdapter().getCount()-1)) //最后一行的样式 setSelector(R.drawable.app_list_corner_round_bottom); else{ setSelector(R.drawable.app_list_corner_shape); } } break; case MotionEvent.ACTION_UP: break; } return super.onInterceptTouchEvent(ev); } }
主要布局类main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:id="@+id/listview_layout" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingBottom="5dp" android:paddingLeft="25dp" android:paddingTop="15dp" > <TextView android:id="@+id/menu_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/setting" android:textColor="@color/gray" /> </LinearLayout> <com.easyway.listview.corner.CornerListView android:id="@+id/list1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:background="@drawable/shape_bg_listview" android:cacheColorHint="@null"/> </LinearLayout>
每行的布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <RelativeLayout android:id="@+id/relativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="10dip" android:paddingLeft="15dip" android:paddingRight="5dip" android:paddingTop="10dip" > <TextView android:id="@+id/item_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:textColor="@color/gray" android:textSize="15sp" /> <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="16dp" android:src="@drawable/right" /> </RelativeLayout> </LinearLayout>
主要类:
package com.easyway.listview.corner; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.LinearLayout; import android.widget.SimpleAdapter; /** * Android实现圆角ListView示例 * 实现圆角ListView原理主要采用添加相关的样式布局。 * 通过重写ListView中特定的方法 * 拦截触摸事件的方法。 * public boolean onInterceptTouchEvent(MotionEvent ev) * 根据横轴坐标计算行数,并实现 * * @Title: * @Description: 实现TODO * @Copyright:Copyright (c) 2011 * @Company:易程科技股份有限公司 * @Date:2012-7-16 * @author longgangbai * @version 1.0 */ public class RoundCornerActivity extends Activity { private CornerListView cornerListView = null; private ArrayList<HashMap<String, String>> maplist = null; private LinearLayout linearLayout; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //设置布局 setContentView(R.layout.main); //获取布局对象 linearLayout=(LinearLayout)findViewById(R.id.listview_layout); //设置壁纸为背景图片 linearLayout.setBackgroundDrawable(getWallpaper()); //获取初始化数据 maplist=getData(); //创建一个适配器对象 SimpleAdapter adapter1 = new SimpleAdapter(this, maplist, R.layout.simple_list_item_1, new String[] { "item" }, new int[] { R.id.item_title }); //创建ListView对象 cornerListView = (CornerListView) findViewById(R.id.list1); //设置适配器 cornerListView.setAdapter(adapter1); initListener(); } private void initListener() { //添加响应时间 cornerListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (arg2 == 0) { System.out.println("0"); }else{ System.out.println("1"); } } }); } /** * 模拟数据 * @return */ public ArrayList<HashMap<String, String>> getData() { maplist = new ArrayList<HashMap<String, String>>(); HashMap<String, String> map1 = new HashMap<String, String>(); HashMap<String, String> map2 = new HashMap<String, String>(); HashMap<String, String> map3 = new HashMap<String, String>(); HashMap<String, String> map4 = new HashMap<String, String>(); map1.put("item", "公交"); map2.put("item", "火车"); map3.put("item", "地铁"); map4.put("item", "航空"); maplist.add(map1); maplist.add(map2); maplist.add(map3); maplist.add(map4); return maplist; } }