自定义View的套路包括以下四种。
绘制效果型
直接使用 Canvas 添加绘制效果是最简单的一种套路。例如BaiduWave的效果不过是通过截断 Canvas 来实现的。

又比如SubmitButton的动画效果看起来很华丽,但可以将其过程拆成几段分别进行绘制。

PatternLockView
PatternLockView 的绘制效果还与触摸事件有关,属于此类型中较为复杂的。
偷梁换柱型
偷梁换柱型指的是在原生的系统控件上添加或替换控件,典型的例子就是 BadgeView。

BadgeView 是怎样实现给已经存在的控件“打上”标记呢?
将原来的控件(如 ImageView)从视图树中移除,但记录它的布局参数,ID等信息。而后新建一个 FrameLayout ,将ImageView 和准备好的角标加入这个布局,最后将 FrameLayout 添加到视图树中去,并复原它的 id ,布局参数等信息。
实际上要实现 Badger 效果,完全可以靠扩展控件的 onDraw 方法来实现,不过这种实现没有通用性。
升级版的BadgeView还实现了动画效果。

AndroidResideMenu

AndroidResideMenu 在Activity的根布局中插入新布局,点击后用动画。还要处理 Activity 的 dispatchTouchEvent方法。
ShowcaseView

TapTargetView

TapTargetView 显示 SpannableString作为提示。
GuillotineMenu-Android

这个库的交互方式非常有意思,它将换上的布局旋转-90度隐藏起来,而后执行动画显示。难点在于如何处理遮挡NaviMenu的问题。
组合排列型
组合排列型是将几种控件组合在容器中,也是较为简单和常用的方法。
SpaceTabLayout

这里是将组合和绘制结合在一起了。
AndroidTreeView
这个树结构的View是纯粹的排列组合式,不过特殊之处在于要设计节点的的数据结构,即树。节点的抽象类TreeNode如下
1 | public class TreeNode { |
各层的容器实际是 LinearLayout。获得根节点后,将每一个子节点中的布局添加进去即可,唯一值得注意的是这个一个递归过程,你还可以决定是否要扩展或收缩整个布局以及是否使用动画效果。
动画驱动型
动画驱动型泛指为添加动画行为,与其它几种类型可以同时使用。例如 KenBurnsView就是在ImageView上应用属性动画而已。

在比如SparkButton是对自定义的绘制效果使用动画。
FloatingView

FloatingView 是偷懒换柱的实现,兼备动画效果。
FloatingView 在 DecorView 上添加了一层 FrameLayout,确定 anchorView 在屏幕上的位置将其在添加的FrameLayout上复制,并执行动画。
1 | Rect rect = new Rect(); |
类似的是HeartLayout

folding-cell-android

使用翻页动画来显示简介和详情,有意思的交互。
FoldingCell 本身是一个容器,将若干个布局折叠存放起来,点击时对这些页执行动画。
AndroidFillableLoaders

VectAlign

AndroidViewHover

Grav

综合使用
例如Context-Menu这个库同时使用了偷梁换柱和组合排列,还添加了动画效果。

有一些效果有多种实现方式,例如文字的跑马灯效果,可以纯粹绘制路径的方式实现,也可以用控件的组合的方式实现。
MarqueeLayoutLibrary将控件并排排列,每一个子控件的尺寸都与容器相同,利用 Scroller 产生滚动效果。

则采用直接绘制的方式完成。
DiagonalLayout

StepView

StepView 是组合控件兼顾了绘制效果,它本身是一个 LinearLayout,容纳的布局如下
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
其中RelativeLayout负责容纳TextView控件, HorizontalStepsViewIndicator 负责绘制效果。
NavigationTabBar

TapBarMenu
