StateBackgroundUtil - 仅使用一张资源图片为View设置具有按下效果的背景

该篇文章主要介绍,如何使用一张资源图片为 View 设置具有按下效果的 background drawable. 

缘起

前段时间在开发项目新版本的过程中,设计师出了一套项目的按下效果规范。规范大概是这样的。

对于一般的按钮,按钮按下的效果只有两种不同的实现。

1、按下后将前置背景图片变暗,具体就是在正常状态的 drawable 上面增加一层 20% 的黑色遮罩。

2、按下后降低前置背景资源透明度,具体就是在按下时改变正常状态的 drawable 透明度为原来的 70% 。

很明显,这套规范会带来以下好处。

  • 设计师在出图时只需要出一张图,然后只需要告诉开发人员对应的按下效果策略,这样可以减轻设计师的出图负担。
  • 客户端这边也是,不需要因为实现一个按下效果而导入两张资源图片,这样在减小包大小的同时也省去了客户端开发人员去写 selector 文件的麻烦。

实现方案

其实在之前的开发过程中,我也曾有过这样的思考,想怎么可以根据一张图来设置 View 的背景,并让他具有按下效果。一开始自然而然的想到了处理 View 的 touch 事件,然后在按下时动态的根据正常背景设置按下后的背景资源。

但是后来觉得还是麻烦,而且一些时候一些 View 本身就需要处理 touch 事件,会造成冲突,所以当时也就一了百了。

这次经过一些搜索,思考,最终使用 StateListDrawable 达到了了目标效果。

StateListDrawable 有一个方法 addState 用于设置不同状态下的 drawable ,包括按下、聚焦、不可用等等所有的状态。

所以结合需求,这里只需要根据正常状态下的 drawable 计算出按下状态的 drawable,然后设置给按下按下状态,就可以完美实现一套资源实现 View 的按下状态。

具体实现

方案已经说清楚了,实现其实很简单,代码如下所示。


  1. private static Drawable getBackground(@NonNull Context context, @DrawableRes int res, @StatePressedMode.Mode int mode, @FloatRange(from = 0.0f, to = 1.0f) float alpha) { 
  2.     Drawable normal = context.getResources().getDrawable(res); 
  3.     Drawable pressed = context.getResources().getDrawable(res); 
  4.     pressed.mutate();    //根据不同的按下要求设置不同的按下drawable 
  5.     setPressedStateDrawable(mode, alpha, pressed);    final StateListDrawable stateListDrawable = new StateListDrawable();    //按下状态 
  6.     stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressed);    //正常状态 
  7.     stateListDrawable.addState(new int[]{}, normal);    return stateListDrawable; 
  8. }  

根据不同按下模式,处理按下的 drawable


  1. private static void setPressedStateDrawable(@StatePressedMode.Mode int mode, @FloatRange(from = 0.0f, to = 1.0f) float alpha, @NonNull Drawable pressed) {    switch (mode) {        case StatePressedMode.ALPHA: 
  2.             pressed.setAlpha(convertAlphaToInt(alpha));            break;        case StatePressedMode.DARK: 
  3.             pressed.setColorFilter(alphaColor(Color.BLACK, convertAlphaToInt(alpha)), PorterDuff.Mode.SRC_ATOP);            break;        default: 
  4.             pressed.setAlpha(convertAlphaToInt(alpha)); 
  5.     } 

目前该方案的实现已经放在了 GitHub, StateBackgroundUtil ,欢迎观摩支持。

一些细节

在设置按下状态的 drawable 时,


  1. Drawable normal = context.getResources().getDrawable(res);
  2. Drawable pressed = context.getResources().getDrawable(res);  

这里的 normal 和 pressed 使用的资源 res 资源是同一个 id。但是由于 drawable 在加载过程中,同一个 res 资源只要在内存中加载过一次,这个 drawable 对应的 state 就会保持一致,所以这里要对 pressed 进行可变设置。


  1. pressed.mutate(); 

关于 mutate 方法的官方说明

This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state;

注意:由于 View 的按下效果只有在设置了 clickable 为 true 时才可以看到效果,所以当你使用 StateBackgroundUtil 为 View 设置背景后却发现没有按下效果,你应该知道怎么办。

不足

  • 目前不支持不可点击状态
  • 不支持颜色背景(当然你可以通过 shape 曲线救国)

最后,如果你发现还有什么问题,欢迎在 issue 或者评论区指出,也欢迎你把更好的方案 PR 上来。

本文作者:佚名

来源:51CTO

时间: 2024-11-01 06:20:27

StateBackgroundUtil - 仅使用一张资源图片为View设置具有按下效果的背景的相关文章

网曝抚顺县旅游局网站仅是一张静态图片

新华网沈阳12月12日电(记者 罗捷)近日网曝辽宁 抚顺县旅游局网站仅是一张 静态图片,有媒体报道称所有链接都无法打开,但页面下方却标注"您是第00174598位访问者". 网友调侃其为"年度最牛政府网站".抚顺县旅游局回应称,这是由于从11月4日起网站进行安全技术整改所致.抚顺县旅游局局长李英说,抚顺县旅游局网站是抚顺市旅游局下设的二级网站,2013年11月4日,抚顺市公安局网络警察支队下达了一份对该网站"信息系统安全保护"的整改通知书,旅游局

Core Animation一些Demo总结 (动态切换图片、大转盘、图片折叠、进度条等动画效果)_Android

前一篇总结了Core Animation的一些基础知识,这一篇主要是Core Animation 的一些应用,涉及到CAShapeLayer.CAReplicatorLayer等图层的知识. 先看效果图: 1.切换图片: 2.彩票转盘 3.图片折叠 4.进度条旋转 5.粒子效果 一.切换图片 看起来很复杂的动画,通过少量的计算和编码就可以简单的实现.要做到这一步,必须是需要研究iOS开发中的Core Animation和Core Graphics框架的.日常工作中,对于很多东西不求甚解,只是拿过

图片显示-Android 项目中不能显示两张以上图片

问题描述 Android 项目中不能显示两张以上图片 public class MainActivity extends Activity { private ImageView[] img=new ImageView[4];//声明一个保存ImageView组件的数组 private int[] imagePath= new int[]{R.drawable.img01,R.drawable.img02,R.drawable.img03,R.drawable.img04};//声明并初始化一个

Android开发中 页面加载一张超大图片(561kb)时出现OOM

今天做项目,发现需要显示一张超大图片,处理过后,还有561Kb      加载的时候,就crash --- OOM      shortMsg:java.lang.OutOfMemoryError      longMsg:java.lang.OutOfMemoryError: bitmap size exceeds VM budget      stackTrace:java.lang.OutOfMemoryError: bitmap size exceeds VM budget      a

请问:U-boot可以设置多张开机图片,并能够轮转显示吗?如何做?

问题描述 请问:U-boot可以设置多张开机图片,并能够轮转显示吗?如何做? 请问:U-boot可以设置多张开机图片,并能够轮转显示吗?如何做? 解决方案 flash上放入多个bmp图片,或者懒一点多加几个分区. 当某个分区的某个文件flag为1的时候,就显示这个分区的bmp图像. 显示和读取的接口可以参考原始的接口.

flash-FLASH支持大几百张位图图片和两个场景的交互会卡吗?

问题描述 FLASH支持大几百张位图图片和两个场景的交互会卡吗? FLASH支持大几百张位图图片和两个场景的交互会卡吗?如果会卡,那我想只用一个场景实现下列效果:这个场景中有一个影片剪辑元件1存于一帧中,不是首帧.该影片剪辑元件1内部嵌套有影片剪辑元件2,影片剪辑元件2内有许多关键帧.我可以为影片剪辑元件内部每一帧均添加一个相同按钮,想通过点击这个按钮画面就会跳转到影片剪辑元件1的首帧,这个按钮应该添加什么代码? 解决方案 没有必要一次性装载所有的图片,而是只装载当前视图中可以看到的图片,这样可

未来大数据存储:1PB仅需一张光盘

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;     以后数据存储无论个人用户,抑或不同规模的企业政府机关等,都可更加轻松地进行.来自斯威本科技大学(SwinburneUniversityofTechnology)的研究团队负责人MinGu教授最新开发出了一种全新的数据存储方式,可将1PB(1024TB)的数据存储到一张仅DVD大小的聚合物碟片上. 大数据存储在当今世界已经显得尤为必要,而且我们人类自步入数字时

在Android开发中替换资源图片不起作用的解决方法_Android

现象 在android开发中,经常会需要替换res\drawable中的图片,打开res\layout下的文件预览布局页面发现图片已经被替换,但在模拟器或者真实机器上运行时发现该图片并没有被替换,还是使用的是原来的资源图片. 原因 在开发过程中,由于使用模拟器测试了程序,在首次运行后会将res文件夹下的图片资源文件(如drawable-hdpi.drawable-ldpi和drawable-mdpi)拷贝到bin文件夹下.在替换资源图片后,eclipse并不清楚是否有图片改变,所以会使用原来bi

javascript-通过js我已经实现了截取一定区域的图片(图片一共7张),如何把这些截取的图片保存到本地指定路径下

问题描述 通过js我已经实现了截取一定区域的图片(图片一共7张),如何把这些截取的图片保存到本地指定路径下 我自己通过js已经实现截取一定区域的图片一共7张图片.但是如何把这7张图片保存到本地的指定目录下.请大神指教~~~ 解决方案 AndEngine实现屏幕截取和图片保存通过正则表达式来截取图片路径屏幕区域截取图片的实现 解决方案二: 用最新的google浏览器可以实现file保存等功能,要通用的话,建议还是服务器上提供下载.