本文由 伯乐在线 - 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. CSS用border绘制三角形

    使用border绘制三角形的思路,就是border尺寸设置一个较大的值,元素自身的宽高设置为0,全部由边线占据,这样每边就会显示为四分之一块的三角形.这样不借助图片,可以直接绘制出三角形了. 一个栗子 ...

  2. JS常用的设计模式(13)——组合模式

    组合模式又叫部分-整体模式,它将所有对象组合成树形结构.使得用户只需要操作最上层的接口,就可以对所有成员做相同的操作. 一个再好不过的例子就是jquery对象,大家都知道1个jquery对象其实是一组 ...

  3. boost: tcp client sample

    #include <boost/asio.hpp> #include <iostream> using namespace std; using namespace boost ...

  4. iOS 获取当前城市

    1.倒入头文件 #import <CoreLocation/CoreLocation.h> 2.实现定位协议CLLocationManagerDelegate 3.定义定位属性  @pro ...

  5. 前端开发之-------------合理利用CSS的权重----------------

    什么是CSS的权重?对于前端工程师来说,这是一个很基础的问题,如果前端工程师没有深刻理解这个概念,则很难写出高质量的CSS代码. 那么到底什么是CSS的权重呢?我们又怎么来进行判定CSS的权重呢? 讨 ...

  6. 破解source insignt方法

    source insignt版本:官网3.5版本 方法:在桌面建立一个文本文档,将下面内容拷贝进去,保存为.reg文件(注意拓展名问题,自己设置),然后双击即可. win7  64bit Window ...

  7. 关于SQL表联接

    以SQL2008为例,Microsoft SQL Server 2008支持四种表运算符-JOIN,APPLY,PIVOT,UNPIVOT.JOIN表运算符是ANSI标准,而其他三种是T-SQL对标准 ...

  8. silverlight 退出系统(关闭当前网页),通过调用JS

    确认后直接退出系统,关闭当前页面 页面部分: <HyperlinkButton x:Name="LinkExit" Style="{StaticResource L ...

  9. 使用notiy和wait模拟阻塞队列

    public class MyQueue { //定义一个存储数据的容器 private LinkedList<Object> list = new LinkedList<Objec ...

  10. php文件hash算法,秒传原理

    header('Content-type:text/html;Charset=UTF-8'); define('blockSize', 4*1024*1024); var_dump(fileHash( ...