自定义图片,实现透明度动态变化

简介: The Use Case In Fragment, there are a couple of places where we use horizontal scrollers as a selection view.

The Use Case

In Fragment, there are a couple of places where we use horizontal scrollers as a selection view. This means that the center icon is the “selected” icon, and items should transition in and out of this state fluidly. For this we decided that a nice reveal transition would be great.

 

 

While this wasn’t entirely necessary, I felt that it was a effect that made the motion feel very fluid and added a touch of class to the app. I could have set up multiple image views and make parts of them individual, but this was the perfect place for a custom drawables.

Customizing Drawables

Drawables in Android are actually very similar to Views. They have similar methods for things like padding and bounds (layout), and have a draw method that can be overridden. In my case, I needed to be able to transition between two drawables, a selected drawable and an unselected drawable, based on a value.

In our case, we simply create a subclass of Drawable that contains other Drawables (and an orientation).

1
2
3
4
5
6 7 8 9 
public class RevealDrawable extends Drawable {  public RevealDrawable(Drawable unselected, Drawable selected, int orientation) {  this(null, null);   mUnselectedDrawable = unselected;  mSelectedDrawable = selected;  mOrientation = orientation;  } } 

Next we need to be able to set the value identifying where the drawable is in the selection process. Fortunately Drawable has a facility for this type of thing built in, setLevel(int).

A Drawable’s level is an integer between 0 and 10,000 which simply allows the Drawable to customize it’s view based on a value. In our case, we can simply define 5,000 as the selected state, 0 and entirely unselected to the left, and 10,000 as entirely unselected to the right.

All we need to do now is to override the draw(Canvas canvas) method to draw the appropriate drawable by clipping the canvas based on the current level.

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 
@Override
public void draw(Canvas canvas) {   // If level == 10000 || level == 0, just draw the unselected image  int level = getLevel();  if (level == 10000 || level == 0) {  mRevealState.mUnselectedDrawable.draw(canvas);  }   // If level == 5000 just draw the selected image  else if (level == 5000) {  mRevealState.mSelectedDrawable.draw(canvas);  }   // Else, draw the transitional version  else {  final Rect r = mTmpRect;  final Rect bounds = getBounds();   { // Draw the unselected portion  float value = (level / 5000f) - 1f;  int w = bounds.width();  if ((mRevealState.mOrientation & HORIZONTAL) != 0) {  w = (int) (w * Math.abs(value));  }  int h = bounds.height();  if ((mRevealState.mOrientation & VERTICAL) != 0) {  h = (int) (h * Math.abs(value));  }  int gravity = value < 0 ? Gravity.LEFT : Gravity.RIGHT;  Gravity.apply(gravity, w, h, bounds, r);   if (w > 0 && h > 0) {  canvas.save();  canvas.clipRect(r);  mRevealState.mUnselectedDrawable.draw(canvas);  canvas.restore();  }  }   { // Draw the selected portion  float value = (level / 5000f) - 1f;  int w = bounds.width();  if ((mRevealState.mOrientation & HORIZONTAL) != 0) {  w -= (int) (w * Math.abs(value));  }  int h = bounds.height();  if ((mRevealState.mOrientation & VERTICAL) != 0) {  h -= (int) (h * Math.abs(value));  }  int gravity = value < 0 ? Gravity.RIGHT : Gravity.LEFT;  Gravity.apply(gravity, w, h, bounds, r);   if (w > 0 && h > 0) {  canvas.save();  canvas.clipRect(r);  mRevealState.mSelectedDrawable.draw(canvas);  canvas.restore();  }  }  } } 

With that, we can simply set the level of the icon based on scroll position and away we go.

1
2
3
4
5
6 
float offset = getOffestForPosition(recyclerView, position); if (Math.abs(offset) <= 1f) {  holder.image.setImageLevel((int) (offset * 5000) + 5000); } else {  holder.image.setImageLevel(0); } 

If you’d like to see the source for this custom drawable, you can find the Gist on Github here

源码: https://gist.github.com/rharter/34051da57f8a6a0991ff

博客地址:http://ryanharter.com/blog/2015/04/03/custom-drawables/

 

目录
相关文章
|
Android开发
eclipse控制台中文输出乱码解决方法
eclipse控制台中文输出乱码解决方法
440 0
|
消息中间件 人工智能 Cloud Native
社区胜于代码,我们在阿帕奇软件基金会亚洲大会聊了聊开源中间件的未来
阿帕奇基金会亚洲大会顺利召开,阿里云消息技术负责人林清山在主论坛做了《阿里云中间件持续进化:从分布式应用架构向云原生 AI 原生应用架构全面升级》的演讲,从云厂商的视角分享了贡献开源、推动社区发展的过程,希望通过 AI 开发框架+AI 观测能力+AI 网关 + 事件驱动,一站式助力大模型应用落地。
418 99
社区胜于代码,我们在阿帕奇软件基金会亚洲大会聊了聊开源中间件的未来
|
10月前
|
运维 Devops 应用服务中间件
自动化运维的利器:Ansible实战指南
【10月更文挑战第36天】在快速迭代的数字时代,自动化运维成为提升效率、减少错误的关键。Ansible以其简洁性、易用性和强大的功能脱颖而出。本文将带你了解Ansible的核心组件,通过实际案例深入其应用,并探讨如何结合最佳实践优化你的自动化工作流程。无论你是新手还是有经验的运维人员,本指南都将为你提供宝贵的知识和技能。
|
11月前
|
JavaScript 前端开发 网络架构
什么是rest参数?
什么是rest参数?
|
JavaScript 程序员
Ant Design Vue中有关父子组件进行通信传值的问题
Ant Design Vue中有关父子组件进行通信传值的问题
263 0
|
Web App开发 缓存 应用服务中间件
HttpServletResponse详情
HttpServletResponse 第一章 HTTP响应详解 前面的文章我们学习了HTTP请求协议及HttpServletRequest对象,今天我们来学习HTTP协议中的另一部分:HTTP响应协议及HttpServletResponse对象。 1、HTTP响应报文 HTTP是基于请求和响应的协议,一次请求对应一次响应。请求和响应的数据格式都遵从HTTP的超文本传输协议。与HTTP的请求一样,HTTP响应的数据也分为3部分:响应行 ,响应头 ,响应体 这3部分组成。请求是通过浏览器将数据传送到服务器,而响应是将服务器处理的结果回送到浏览器。 2、使用抓包工具查看响应数据 创建一个we
319 1
|
NoSQL Java 程序员
为什么引入Redisson分布式锁?
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包含了各种各样的分布式锁的实现。
为什么引入Redisson分布式锁?
|
存储 编解码 监控
基于Python的屏幕监控软件
屏幕监控软件的实现涉及到复杂的操作和权限,同时也涉及到隐私和合法性的问题。这是一个基于Python的小示例,展示如何使用第三方库pyautogui来截屏并保存截图
893 0
|
Apache Windows
Apache No installed service named “Apache2.4“的解决办法
Apache No installed service named “Apache2.4“的解决办法
429 0
|
运维 监控 容灾
安全生产-系统稳定性建设
安全是产品的底座,是体验的基础,也是企业的一项核心竞争力。安全生产是一项系统性的工作,同时也是一件比较琐碎的事,需要做方方面面的考虑尽一切可能保障系统安全稳定运行。
安全生产-系统稳定性建设