为了有更好的UI体验,一般我们会把button、textview等控件的背景设置上阴影。传统的做法是美工提供一张具有阴影效果的nine patch图,然后将其在xml文件中添加到background属性。这种做法没有问题,不过缺乏灵活性。

图1.使用代码生成的具有“阴影”效果的控件

在android中,每一种在xml文件中定义的图片,均可以使用java代码生成,其中LayerDrawable对应的xml文件的根元素为<layer-list>。

首先我介绍一下使用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>

解析:

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);
源码为:
 /** Specify modifiers to the bounds for the drawable[index].
left += l
top += t;
right -= r;
bottom -= b;
*/
public void setLayerInset(int index, int l, int t, int r, int b) {
ChildDrawable childDrawable = mLayerState.mChildren[index];
childDrawable.mInsetL = l;
childDrawable.mInsetT = t;
childDrawable.mInsetR = r;
childDrawable.mInsetB = b;
}

可以看出setLayerInset()函数的作用就是将某层(层数从0开始计数)相对于上一层进行向里偏移。当然如果传入的数值为负数,就是向外偏移了,不过这时上层就遮挡住下层了,失去了使用layer的意义了。

4.padding的作用同样非常重要:

(1)当在最上层使用padding时,它指明的是最上层的drawable边缘与内容之间的padding;

(2)当在非最上层使用padding时,它指明当前层与上层之间的padding。

下面使用java代码生成LayerDrawable。

 private void setLayerBg(View view){

         int radius0 = 10;
float[] outerR = new float[] { radius0, radius0, radius0, radius0, radius0, radius0, radius0, radius0 };
RoundRectShape roundRectShape0 = new RoundRectShape(outerR, null, null); int radius1 = 10;
float[] outerR1 = new float[] { radius1, radius1, radius1, radius1, radius1, radius1, radius1, radius1 };
RoundRectShape roundRectShape1 = new RoundRectShape(outerR1, null, null); ShapeDrawable shapeDrawableBg = new ShapeDrawable(); shapeDrawableBg.setPadding(0, 0, 0, 0);
shapeDrawableBg.setShape(roundRectShape0); shapeDrawableBg.getPaint().setStyle(Paint.Style.FILL);
shapeDrawableBg.getPaint().setColor(0xffbbbbbb); ShapeDrawable shapeDrawableFg = new ShapeDrawable(); shapeDrawableFg.setPadding(23, 23, 23, 23);
shapeDrawableFg.setShape(roundRectShape1); shapeDrawableFg.getPaint().setStyle(Paint.Style.FILL);
shapeDrawableFg.getPaint().setColor(0xffdddddd); Drawable[] layers = {shapeDrawableBg, shapeDrawableFg};
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setLayerInset(1, 0, 0, 1, 1); view.setBackgroundDrawable(layerDrawable); }

注释我就不写了,具体的解释见上面的解析。

LayerDrawable和StateListDrawable相结合使用

当我们遇到可点击的控件时,需要给此控件自定义几个不同状态的background,比如按下效果、普通状态效果,这时就需要用到StateListDrawable。

采用LayerDrawable生成的图片具有的只是静态属性,当将不同状态的LayerDrawable添加到一个StateListDrawable中,这样控件不同状态时均选择是否具有阴影效果。

代码如下:

 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); text = (TextView)this.findViewById(R.id.text);
text.setBackgroundDrawable(getStateListDrawable());
text.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "ttt", Toast.LENGTH_SHORT).show();
}
});
} private Drawable getStateListDrawable(){ StateListDrawable stateListDrawable = new StateListDrawable(); int[] stateHighlighted = new int[]{android.R.attr.state_pressed};
Drawable highlightedDrawable = getLayerDrawable(0xffcccccc);
stateListDrawable.addState(stateHighlighted, highlightedDrawable); int[] stateNormal = new int[]{};
Drawable normalDrawable = getLayerDrawable(0xffdddddd);
stateListDrawable.addState(stateNormal, normalDrawable); return stateListDrawable;
} private Drawable getLayerDrawable(int foregroundColor){ int radius0 = 10;
float[] outerR = new float[] { radius0, radius0, radius0, radius0, radius0, radius0, radius0, radius0 };
RoundRectShape roundRectShape0 = new RoundRectShape(outerR, null, null); int radius1 = 10;
float[] outerR1 = new float[] { radius1, radius1, radius1, radius1, radius1, radius1, radius1, radius1 };
RoundRectShape roundRectShape1 = new RoundRectShape(outerR1, null, null); ShapeDrawable shapeDrawableBg = new ShapeDrawable();
shapeDrawableBg.setPadding(0, 0, 0, 0);
shapeDrawableBg.setShape(roundRectShape0);
shapeDrawableBg.getPaint().setStyle(Paint.Style.FILL);
shapeDrawableBg.getPaint().setColor(0xffbbbbbb); ShapeDrawable shapeDrawableFg = new ShapeDrawable();
shapeDrawableFg.setPadding(23, 23, 23, 23);
shapeDrawableFg.setShape(roundRectShape1);
shapeDrawableFg.getPaint().setStyle(Paint.Style.FILL);
shapeDrawableFg.getPaint().setColor(foregroundColor); Drawable[] layers = {shapeDrawableBg, shapeDrawableFg};
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.setLayerInset(1, 0, 0, 1, 1); return layerDrawable;
}

需要注意的是:当给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>
												

[原创]android使用代码生成LayerDrawable的方法和注意事项的更多相关文章

  1. 安装Android studio出现'tools.jar' seems to be not in Android Studio classpath......的解决方法

    安装Android studio出现'tools.jar' seems to be not in Android Studio classpath......的解决方法 原创 2015年07月31日 ...

  2. [原创]Android Monkey测试工具使用介绍

    [原创]Android Monkey测试工具使用介绍 1 Android Monkey介绍 Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它向系统发送伪随机的用户事件 ...

  3. Android C代码回调java方法

    本文将讲述下列三种C代码回调java方法 1.c代码回调java空方法 2.c代码回调java int类型参数方法 3.c代码回调javaString类型参数方法 方法都差不多,先看c代码回调java ...

  4. android MediaPlayer API大全已经方法详解(转载)

    通过这张图,我们可以知道一个MediaPlayer对象有以下的状态: 1)当一个MediaPlayer对象被刚刚用new操作符创建或是调用了reset()方法后,它就处于Idle状态.当调用了rele ...

  5. android中的提示信息显示方法(toast应用)

    android中的提示信息显示方法(toast应用) (2011-10-17 11:02:06) 转载▼ 标签: android toast 杂谈 分类: Android android中toast的 ...

  6. 【转】Android中JNI的使用方法

    Android中JNI的使用方法 首先看一下Android平台的框架图:(网上盗用) 可以看到Android上层的Application和ApplicationFramework都是使用Java编写, ...

  7. [Android设计模式]Android退出应用程序终极方法

    如何干净彻底地退出Android应用程序,是很多开发者的心头痒.如何干净地关闭所有已打开的Activity? 如何关闭指定的Activity? 如何关闭一类Activity? 这里,我们提出一种通过实 ...

  8. 我的Android最佳实践之—— Android启动画面的实现方法

    本文实例讲述了Android启动画面的实现方法.分享给大家供大家参考.具体分析如下: 在应用程序中经常用到启动画面,会启动一个后台线程为主程序的运行准备资源.Android要实现启动画面可以这样做: ...

  9. Chrome模拟手机浏览器(iOS/Android)的三种方法,亲测无误!

    大网站都有推出自己的手机访问版本页面,不管是新闻类还是视频网站,我们在电脑是无法直接访问到手机网站的,比如我经常访问一个3g.qq.com这个手机站点,如果在电脑上直接打开它,则会跳转到其它页面,一般 ...

随机推荐

  1. JAVA对象转化JSON出现死循环问题

    主要是解决JSON因Hibernate映射生成的集合的转化出现的死循环问题. 这个方法很重要 public String ajaxJsonByObjectDirecdt(Object obj, Str ...

  2. EntityFramework 中支持 BulkInsert 扩展

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 前言 很显然,你应该不至于使用 EntityFramework 直接插入 10W 数据到数据库中,那 ...

  3. vs emulator for android使用

    在windows上调试android程序,可以利用hyperv虚拟化功能,微软也提供了模拟工具和android studio.eclipse的配置说明,不再累述. 关于启动vs模拟器的cmd命令: e ...

  4. Leetcode 111 Minimum Depth of Binary Tree 二叉树

    找出最短的从叶子到根的路径长 可以回忆Maximum Depth of Binary Tree的写法,只不过在!root,我把它改成了10000000,还有max函数改成了min函数,最后的值如果是1 ...

  5. Android显示等宽图片的问题

    安卓开发常遇到一个问题,就是在listView里面,在不知道图片宽高的前提下,另图片布满屏幕(图片宽度等于屏幕宽度,高度自适应).在listView中,只是设置scaleType,imageView. ...

  6. 线程与并发系列一:Lock、Monitor、UserSpinLock

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  7. c# 字体安装

    [DllImport("kernel32.dll", SetLastError = true)] static extern int WriteProfileString(stri ...

  8. 【转】升级Xcode6.3插件失效解决办法

     1.打开终端,输入以下代码获取到DVTPlugInCompatibilityUUID         defaults read /Applications/Xcode.app/Contents/I ...

  9. Win7快捷方式图标不显示解决办法

    问题:WIN7的系统,桌面.开始菜单以及任务栏的快捷方式图标显示不正常,看不到程序默认图标,快捷方式图标不显示. 解决方法:删除程序图标缓存即可.   将下面的内容复制到记事本保存为“图标缓存清理.b ...

  10. 查看Oracle数据库的用户名和密码

    运行 cmd 按如下输入命令 sqlplus / as sysdba ---------以sys登陆          超级用户(sysdba) alter user 用户名 account unlo ...