本文由 伯乐在线 - treesouth 翻译,toolate 校稿。未经许可,禁止转载! 英文出处:ryanharter.com。欢迎加入翻译小组

我们看过一些博客文章,讲述了为什么要适时地使用自定义的view,以及它们是如何帮你正确地封装应用代码的。却少有人讨论这类思考如何转变为我们的app中与view无关的其它部分。

在我开发的应用程序Fragment里,在一些地方我使用自定义的Drawable封装我的逻辑代码,就像使用自定义view一样。代码放在Gist

用例

在Fragment中,我们使用了水平方向的滑动条作为一些地方的可选的视图区域。这就意味着中央的图标是被选择的图标,每一项都能够以平滑移动的方式移进移出。由此,我们认为最好展现出一个优雅的过渡效果。

然而这并非完全必要。我认为这是一个效果,它使得运动更为流畅,并给应用增加了些许品味。我本可以设置多个图像view并单独呈现,但是这却是自定义drawable的最佳使用场景。

自定义Drawable

在Android中,Drawable实际上是很接近于View。它们有相似的方法获取布局的边距和边界,并且有可以被覆写的draw方法。在我的例子里,我需要在选中和未选中这两个基于值的drawable中实现平移效果。

在我们的例子中,我们简单地创建出来包含了其他Drawables(含方向)的Drawable的子类。

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;
  }
}

接下来,我们需要做的就是设定一个值,用来标明drawable是选中的一栏。恰好Drawable有一个内置函数可以做到这一点,即setLevel(int)。

一个Drawable的级别是从0到10000的整数值,这仅仅允许Drawable根据一个值来定义它的视图。在我们的例子中,我们可以简单地设定5000作为选中状态,0表示左侧完全未选中,10000表示右侧完全未选中。

我们要做的就是重写draw(Canvas canvas)方法,根据当前level值裁剪canvas,从而绘制合适的drawable。

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();
      }
    }
  }
}

就这样,我们仅仅设置了基于滚动位置的水平方向的图标,这事就搞定了。

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);
}

如果你想看到这份自定义Drawable的源代码,你可以在Github的这里查看。

自定义Drawable的更多相关文章

  1. [转]自定义Drawable实现灵动的红鲤鱼动画(下篇)

      小鱼儿 上篇文章自定义Drawable实现灵动的红鲤鱼动画(上篇)我们绘制了可以摆动身体的小鱼,本篇就分享一下如何让小鱼游到手指点击的位置.用到的主要技术如下: 1).三阶贝塞尔曲线 2).Pat ...

  2. [转]自定义Drawable实现灵动的红鲤鱼动画(上篇)

    此篇中的小鱼动画是模仿国外一个大牛做的flash动画,第一眼就爱上它了,简约灵动又不失美学,于是抽空试着尝试了一下,如下是我用Android实现的效果图:   小鱼儿 由于整个绘制分析过程比较繁琐所以 ...

  3. Android APK开发 Drawable文件夹下的自定义Drawable文件

    版本:2018/2/11 Drawable的分类 自定义Drawable SVG矢量图 个人总结的知识点外,部分知识点选自<Android开发艺术探索>-第六章 Drawable 1.Dr ...

  4. Android 自定义Drawable

    1.使用BitmapShader实现图片圆角 public class CornerDrawable extends Drawable { private Paint mPaint; private ...

  5. Android自定义drawable(Shape)详解

    在Android开发过程中,经常需要改变控件的默认样式, 那么通常会使用多个图片来解决.不过这种方式可能需要多个图片,比如一个按钮,需要点击时的式样图片,默认的式样图片. 这样就容易使apk变大. 那 ...

  6. Android 使用自定义Drawable 设置圆角矩形或者圆形图片

    转自  Android Drawable 那些不为人知的高效用法 本文出自:[张鸿洋的博客] http://blog.csdn.net/lmj623565791/article/details/437 ...

  7. Drawable与Bitmap 自定义

    Drawable简介 Drawable是Android平下通用的图形对象,它可以装载常用格式的图像,比如GIF.PNG.JPG,当然也支持BMP.相比于View,我们并不需要去考虑如何measure. ...

  8. Android Drawable 那些不为人知的高效用法

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43752383,本文出自:[张鸿洋的博客] 1.概述 Drawable在我们平时的 ...

  9. Android自定义View之倒计时Countdown实现

    先看一下效果: 在点击OK键之后,开始倒计时. 实现步骤 1.新建Android工程"CountdownView" 2.自定义Drawable 自定义View并没有直接的用户交互, ...

随机推荐

  1. 学习总结 java 异常

    package com.hanqi.ec; public class Test1 { public static void main(String[] args) { int a = 10 , b = ...

  2. bzoj1216 [HNOI2003]操作系统

    1216: [HNOI2003]操作系统 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 751  Solved: 419[Submit][Status ...

  3. 使用Servlet处理请求<http://blog.sina.com.cn/s/blog_5d3fb3cc0100ep9q.html>

    一.GET和POST的区别 1.GET提交的是文本内容,规定其数据长度不超过255个字符.在GET方式提交的URL中会显示出提交的查询数据而却提交数据的缓存会在浏览器的URL历史状态中,这样我们往往在 ...

  4. 父窗口调用iframe子窗口方法

    一.父窗口调用iframe子窗口方法 1.HTML语法:<iframe name="myFrame" src="child.html"></i ...

  5. 对像转成 和 byte 互转类库方法

    using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serializatio ...

  6. Volume serial number could associate file existence on certain volume

    When it comes to lnk file analysis, we should put more emphasis on the volume serial number. It coul ...

  7. [my]_ubuntu12.10_/etc/apt/sources.list

    deb http://mirrors.163.com/ubuntu/ precise main universe restricted multiverse deb-src http://mirror ...

  8. CentOS6.5 python 2.6升级到2.7

    在CentOS6.5下,将自带的python2.6.6升级到python2.7.3,解决方法如下: 下载python2.7.3包,并解压缩,输入命令:#wget http://python.org/f ...

  9. 【转】准确理解CSS clear:left/right的含义及实际用途

    零.说点什么 好久没更新了.并不是在折腾什么大作,而是广度学习与实践中,加上婚礼等诸多大事,所以产出较少. 今天这篇也只是小作,博客是自己很好的学习工具,只要我学习不止,博客也会不断更新的. 我们平时 ...

  10. WCF帮助类

    using BJSW.ZTFX.Client.Silverlight.MapBusinessService; using System.ServiceModel; using System.SL.Ap ...