本文由 伯乐在线 - 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. SQL 实现,如果存在就更新,如果不存在就添加

    alter proc proc_DataSummary as begin begin try begin tran --PV --统计的信息存入临时表 ), CreateDate, ) ), Crea ...

  2. No.002 Add Two Numbers

    Add Two Numbers Total Accepted: 160702 Total Submissions: 664770 Difficulty: Medium You are given tw ...

  3. pb中打开窗口并传递参数

    try long ll_result; ll_result=1;openwithparm(w_sb_order,UserCode);catch(RuntimeError er)  errorMsg=e ...

  4. android Camera使用(一)

    现在的App不可避免的要使用到手机的相机功能 首先我们先来介绍下最简单的一个实现方式,启动系统自带的Activity 上代码: public void openCamera() { Intent i= ...

  5. ios NSString常见的字符串操作 分割 查找

    1.NSString *str = [[NSString alloc]init];     //简单粗暴,基本用不到 2.NSString *str = [[NSString alloc]initWi ...

  6. div模仿select效果二:带搜索框

    项目需要,要做一个首字母快速定位的select,代码如下: HTML <div class="select_country" unselectable="on&qu ...

  7. static 在多台下的特性

    被static修饰的方法不具备多台的特性,因为这个时候,该方法已经不具备"后期绑定"的性质了,也就是说,基类的引用就算指向导出类,调用的static的方法还是用基类的. 如果要调用 ...

  8. PUTTY使用Ctrl+s僵死的问题

    算是分享个小经验吧! 一直都是使用VM+PUTTY的方式调试Linux程序,有时候在Vi中编辑了程序,Windowns下旧习难改,顺手就Ctrl+s了,尽管我知道Vi的保存是:w. 很不幸这时的PUT ...

  9. jLink V8调试exynos 4412 u-boot的几点补充

    /** ****************************************************************************** * @author    Maox ...

  10. Ninject在mvc中的简单配置

    前言 Ninject是一款开源的轻量级的依赖注入插件.从接触ioc以来,一直都是使用这个,感觉用起来还是不错的,配置起来也很方便简单.在mvc中更是基本傻瓜式的配置. 开发前的准备 新建一个mvc3项 ...