源码浅析 - ListViewAnimations

1. 前言

ListViewAnimations 开源库可以让 Android 开发者根据项目实际需求,很方便为 ListView(严格来说 AbsListView 更准确些,因为还包含GridView。但为了方便统称 ListView,下同)添加动画效果。
ListViewAnimations 提供 Alpha,Swing-RightIn,Swing-LeftIn, Swing-BottomIn,Swing-RightIn 和 ScaleIn 等内置动画效果。并支持 StickyListHeaders,Swipe-to-Dismiss 和 Swipe-Undo,Drag-and-Drop 重排序,ExpandableList 等常用功能。开发者可以组合库提供的动画,也可以继承库的抽象类实现自定义的动画。
本文尝试从源代码出发,分析 ListViewAnimations 的实现思路,从而加深对 ListView 的实现,View 的事件分发机制,Android 动画等相关内容的了解。

2. 总体设计

我们知道,ListView 视图的展现方式是无穷尽的,数据来源也是多种多样的,同时人们还有着各式各样的动画需求。这就要求 ListView 具有很好的扩展性。
这里写图片描述
以上是 Android Framework 中 ListView 及相应 Adapter 的类关系图。得益于 Android 团队的良好设计,通过桥接模式很好的解决了对 ListView 复杂多变的需求,也就是通过将抽象部分和实现部分分离解耦,从而使得各自可以适应各种需求变化。同时,还可以发现适配器模式的应用,通过 ListAdapter 定义最基本的目标接口,其他适配器类针对目标接口对数据源进行修饰。例如,SimpleAdapter 提供最简单的适配,ArrayAdapter 对数据源是数组的情况进行适配,CursorAdapter 对数据源是数据库的情况进行适配。ListViewAnimations 正是对此设计的继承和发扬,作者比较巧妙地运用装饰模式,不改变原有类的情况下,对其进行增强,也就是在 getView 方法体内对 item 增加各种动画效果。装饰模式既能动态添加新功能,又有效避免功能组合时的类爆炸。BaseAdapterDecorator 是继承于 BaseAdapter 的抽象装饰类,类中的 mDecoratorBaseAdapter 对象用于保存装饰角色。该类是 ListViewAnimations 的核心,其他具体装饰器都继承于该类并实现 item 的动画功能。

3. 流程图

ListViewAnimations 动画库的使用流程图如下所示。
这里写图片描述
与使用 ListView 的流程基本一致,主要不同的地方在于可以使用一个或多个 BaseAdapterDecorator 类来装饰 BaseAdapter 对象。

4. 详细设计

ListViewAnimations 库的组成部分主要包含三个模块:

4.1 lib-core 模块

ListViewAnimations 的核心模块,主要是各种展示动画部分,下面分别介绍主要类和接口。
BaseAdapterDecorator 类
BaseAdapterDecorator 继承于 BaseAdapter 类,并实现了 SectionIndexer, Swappable, Insertable, ListViewWrapperSetter 接口。ListViewAnimations 库中其他 Adapter 都继承于该类,并根据具体需求实现相应接口中的方法。类关系图如下所示。
这里写图片描述
SectionIndexer 接口声明在 ListView 中的 sections 间快速滚动的方法,Swappable 接口声明实现 ListView 中两个 item 相互交换的方法,Insertable 接口声明给 ListView 添加 item 的方法,ListViewWrapperSetter 接口声明对 AbsListView 进行包装的方法。
该类包含成员变量 mDecoratedBaseAdapter 和成员变量 mListViewWrapper,分别用于保存装饰角色和对应的任意 ListView 包装类实例。其中,setListViewWrapper 方法用于保存 ListView 的包装类实例。

public void setListViewWrapper(@NonNull final ListViewWrapper listViewWrapper) {
    mListViewWrapper = listViewWrapper;
    /** 递归初始化每个装饰角色的 mListViewWrapper */
    if (mDecoratedBaseAdapter instanceof ListViewWrapperSetter) {
        ((ListViewWrapperSetter) mDecoratedBaseAdapter).setListViewWrapper(listViewWrapper);
    }
}

ArrayAdapter 类
继承自 BaseAdapter 类,用于 ArrayList 适配,并实现 Swappable 和 Insertable 接口,也就是说使用该类作为 Adapter,可以实现基本的 item 互换和增加删除 item。

/** 实现 Swappable 接口 */
public void swapItems(final int positionOne, final int positionTwo) {
    T firstItem = mItems.set(positionOne, getItem(positionTwo));
    notifyDataSetChanged();
    mItems.set(positionTwo, firstItem);
}
/** 实现 Insertable 接口 */
public void add(final int index, @NonNull final T item) {
    mItems.add(index, item);
    notifyDataSetChanged();
}

ViewAnimator 类
根据位置判断是否应该给 item 添加动画,并计算动画延时。包含成员变量 mAnimators,类型为 SparseArray,用于保存 item 的动画。

AnimationAdatper 类
BaseAdaperDecorator 的子类,根据用户需求在 getView 方法中为 item 添加 AnimatorSet。包含成员变量 mViewAnimator,通过调用它的 animateViewIfNecessary 方法给 item 添加动画。动画由三部分构成,第一部分,通过 mDecoratorBaseAdapter 的 getAnimators 方法获得装饰器实例的动画;第二部分,获得当前实例的动画;第三部分,Alpha 显示动画。最终 item 执行这三部分的动画组合。

private void animateViewIfNecessary(final int position, @NonNull final View view, 
        @NonNull final ViewGroup parent) {
    ...
    Animator[] childAnimators;
    if (getDecoratedBaseAdapter() instanceof AnimationAdapter) {
        childAnimators = ((AnimationAdapter) getDecoratedBaseAdapter()).getAnimators(parent, view);
    } else {
        childAnimators = new Animator[0];
    }
    Animator[] animators = getAnimators(parent, view);
    Animator alphaAnimator = ObjectAnimator.ofFloat(view, ALPHA, 0, 1);
    /** 将动画组合起来 */
    Animator
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值