AndroidTv Home界面实现原理(二)——Leanback 库的主页卡位缩放动画源码解析
先看个效果图:
上一篇中,我们留了问题,在 Tv Home 界面这种很常见聚焦卡位放大动画效果,我们这一篇就来看看 Leanback 库是怎么实现的。
如果要我们自己实现的话,思路应该不难,就是写个放大、缩小动画,然后在卡位获得焦点时应用放大动画,失去焦点时应用缩小动画,所以关键点只是在于如何进行封装。那下面就来学学 Google Leanback 库的 ItemView 缩放动画的实现思路。
源码分析
看源码时,我习惯带着目的性地去阅读,这样只要专注于理解跟目的相关的代码即可,不用每行代码地去分析,毕竟好多代码目前能力有限,还啃不透。
那么,我们这次阅读源码的目的就是要搞清楚:卡位获得焦点时放大、缩小动画是如何实现的?
阅读源码时经常会碰到一个问题,那就是该从哪入手,从哪开始看?
这就是为什么我习惯带着目的去阅读,因为我们可以从目的分析,猜测我们需要的代码应该在哪里,然后找到我们该从哪里阅读,再一步步的去分析。
比如我们这次的任务,我们该从哪里入手阅读源码呢?首先,你得先了解一下 Leanback 库的基本使用,这就是为什么我第一篇博客先简单介绍了 Leanback 库的使用。在上一篇博客里,可以看到,我们跟 Leanback 库打交道的也就是下面这几个类:
- ArrayObjectAdapter:作用类似于 List,装填着整个页面的数据,页面数据其实是分两级,以行为单位和以每一行中的 Item 为单位,所以整个页面有一个 ArrayObjectAdapter(mRowsAdapter) 对象,它由许多行数据 ArrayObjectAdapter(rowAdapter) 对象组成,每行数据 rowAdapter 由许多 Item 组成。初始化一个 ArrayObjectAdapter 对象时,必须提供一个 Presenter 对象与它关联。
- ListRowPresenter:Leanback 库中的 Presenter 作用都有些类似于 RecyclerView.Adapter,用于创建 ItemView 以及将数据绑定到 ItemView 上。
- ListRow:可以理解成一个 Mode,也就是把每一行抽象封装成一个 ListRow
- BrowerFragment:用来展示可左右上下滑动的视频列表界面,Leanback 已高度封装,我们只需提供一个页面的 ArrayObjectAdapter(mRowsAdapter) 对象,通过
setAdapter()
将数据设置进去,Leanback 会自动根据 ArrayObjectAdapter 里的数据以及和它关联的 Presenter 将界面显示出来。
既然我们跟 Leanback 打交道只有这么几点,那么切入点应该就在这些,毕竟我们对 Leanback 并不熟,那么只能从我们接触到的地方来着手。
那么,再来想想,既然是要实现卡位获得焦点和失去焦点时放大和缩小动画,那么肯定是需要监听 ItemView 的焦点变化,对吧?那我们通常是怎么做的,无外乎就是在 RecyclerView.Adapter 里的 onCreateViewHolder()
或 onBindViewHolder()
里监听 ItemView 的焦点变化吧。
既然方向有了,那么就是要寻找 Leanback Home 界面对应的 RecyclerView.Adapter 是由哪个类实现的吧。我们也知道了在 Leanback 中 Presenter 的作用就是类似于 RecyclerView.Adapter,那么我们就先到 Presenter 里看一下。
ListRowPresenter 继承自 RowPresenter 继承自 Presenter,那么我们通过 Android Studio 跳到 Presenter 里看看。
Presenter 是个抽象类,有三个抽象方法, onCreateViewHolder()、onBindViewHolder()、onUnbindViewHolder()
,跟 RecyclerView.Adapter 很像吧。根据我们之前的分析, ItemView 焦点的监听通常是在 onCreateViewHolder()
或 onBindViewHolder()
里实现的,那么我们就去它的实现类 ListRowPresenter 里看一看。
ListRowPresenter 里找不到这三个方法的实现,那么就是由它的父类 RowPresenter 实现了,我们继续通过 AS 跳到 RowPresenter 里看看。
onCreateViewHolder()
里的代码我们不用去理解,当然你有时间有能力也可以,但现在主要是想搞懂它的卡位缩放动画实现,所以我们只要看有没有跟焦点监听相关的代码即可。很显然,这里面并没有找到,里面调用了几个方法,有些方法一看就知道作用是创建某个对象的,你们也可以点进去看看,这里我们着重看一下 initializeRowViewHolder()
这个方法。
好像也没找到跟焦点监听的相关代码,但是左边有个标志,说明子类 ListRowPresenter 有复写这个方法,那么代码运行时实际上是调用的之类的方法,那么我们就点进去看看。
代码很多,截图也没截完,但是我们发现了一个关键,找到了一个看名字就觉得跟焦点有关的方法 FocusHighlightHelper.setupBrowseItemFocusHighlight()
,那么到底是不是呢?我们继续点击去看一下。
这个方法的介绍大意就是说设置每行的 ItemView 即卡位获得焦点时的行为,这不就是指卡位的缩放动画嘛,看来我们找到了。看代码,是调用了 ItemBridgeAdapter 的 setFocusHighlight()
方法,继续跟进看一下。
方法就只是设置了 mFocusHighlight 变量的值,而 ItemBridgeAdapter 是继承 RecyclerView.Adapter 的,看来卡位的焦点监听就是在这里实现了。看一下 onCreateViewHolder()
方法就知道是不是了。
presenterView 其实就是在 Presenter 里创建出来的 ItemView,所以这里其实就是对卡位设置焦点的变化监听,viewHolder.mFocusChangeListener 应该是 View.OnFocusChangeListener 的对象,我们看一下。
mFocusChangeListener 初始化通过实例化一个类对象赋值,那么这个类应该就是实现 View.OnFocusChangeListener 接口的,我们继续看一下。
这下清楚了吧,焦点发生变化时,会去调用 mFcousHightlight 的 onItemFocused()
方法。而 mFcousHightlight 是之前 FocusHighlightHelper.setupBrowseItemFocusHighlight()
里调用了 ItemBridgeAdapter 的 setFocusHighlight()
方法传进来的,我们再看看它传进来的是什么。
看一下 BrowseItemFocusHighlight 这个类做了什么。
所以,在 ItemBridgeAdapter 里注册了焦点变化监听,当焦点变化时,通知 mFcousHightlight 执行 onItemFocused()
方法,而 mFcousHightlight 是 BrowseItemFocusHighlight 类的实例,所以实际上是来执行上图里的逻辑。看代码也很容易明白,设置 ItemView 的选中状态,并且去运行一个焦点动画,那么卡位的缩放动画应该就是在这里实现了。继续看一下是不是。
该方法其实就是创建一个动画对象,如果该对象有缓存的话,那么就从缓存中取出,没有的话,就 new 一个,这种缓存的思想很值得学习。
该类就是实现了缩放的动画效果了,通过实现 TimeAnimator.TimeListener 接口来实现的属性动画,当然缩放动画也可以用其他方式实现,无非就是对 View 进行放大、缩小而已,这里就不具体去分析了,感兴趣的可以自己来这里看看 Google 是如何实现缩放动画的,后期有时间的话我可以再来分析一下这个类。
好了,到这里基本就分析完了,Leanback 库关于卡位的缩放动画的实现,从我们要从哪里着手开始阅读源码到找到焦点监听实现的相关代码到动画实现的代码整个过程基本就是这样。以后大家在想看源码的某个功能是如何实现时,可以参考这种思路来进行分析,一步步的去跟进,只找我们目标相关的代码,这样可以不至于被整个源码的复杂性混乱掉。
最后,我想再总结一下上面的过程。
总结
- 卡位缩放动画的实现在类 FocusHighlightHelper 的内部类 FocusAnimator 里实现。
- 缩放动画跟 ItemView 的绑定过程:
RowPresenter#onCreateViewHoler()
-> RowPresenter#initializeRowViewHolder()
-> ListRowPresenter#initializeRowViewHolder()
-> FocusHighlightHelper#setupBrowseItemFocusHighlight()
-> ItemBridgeAdapter#setFocusHighlight() - 简单点说就是,当每一行的 View 要创建时,会注册一个焦点监听器,该行里的 ItemView 焦点发生变化时会从 ItemViwe 的 Tag 里取出缩放动画对象,如果没有则 new 一个,然后应用缩放动画。
AndroidTv Home界面实现原理(二)——Leanback 库的主页卡位缩放动画源码解析的更多相关文章
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Android 热修复Nuwa的原理及Gradle插件源码解析
现在,热修复的具体实现方案开源的也有很多,原理也大同小异,本篇文章以Nuwa为例,深入剖析. Nuwa的github地址 https://github.com/jasonross/Nuwa 以及用于 ...
- 顺序线性表 ---- ArrayList 源码解析及实现原理分析
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...
- dubbo源码解析五 --- 集群容错架构设计与原理分析
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...
- 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试
机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...
- Generator函数执行器-co函数库源码解析
一.co函数是什么 co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行.短小精悍只有短短200余行,就可以免去手动编写G ...
- 【Java实战】源码解析Java SPI(Service Provider Interface )机制原理
一.背景知识 在阅读开源框架源码时,发现许多框架都支持SPI(Service Provider Interface ),前面有篇文章JDBC对Driver的加载时应用了SPI,参考[Hibernate ...
- Laya Timer原理 & 源码解析
Laya Timer原理 & 源码解析 @author ixenos 2019-03-18 16:26:38 一.原理 1.将所有Handler注册到池中 1.普通Handler在handle ...
- Spring事务源码解析(二)获取增强
在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagemen ...
随机推荐
- JavaScript中的几种继承方式对比
转自:http://blog.csdn.net/kkkkkxiaofei/article/details/46474069 从’严格’意义上说,JavaScript并不是一门真正的面向对象语言.这种说 ...
- (转)Schema
总结: 1.schema本身就是一个XML文件 2.schema功能比DTD强大,正逐步替代DTD 3.schema的根元素固定为schema 4.schema文档定义完毕后,需要绑定到一个URI地址 ...
- Java操作Excel和Word
这是一个URL它提供了Java项目所推荐的处理此项目所用的类库 http://www.oschina.net/project/tag/258/excel-tools?company=0&sor ...
- JavaScript的六种继承方式
继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的 原型链 首先得要明白什么是原型链,在一篇文章看懂proto和prototype ...
- 引水入城[NOI2010 ]
题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N行M列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了 ...
- spring集成mybatis实现mysql读写分离
前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...
- web端常见安全漏洞测试结果分析-- appscan
基于appscan测试结果分析: 一.XSS跨站脚本 指的是攻击者往Web页面里插入恶意html代码,通常是JavaScript编写的恶意代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被 ...
- Fancytree Javascript Tree的入门使用
Fancytree Javascript Tree的入门使用 一.概念----是做什么的能干什么 Fancytree是一个Javascript控件,它依赖于: <script src=" ...
- Cordova + idea 环境搭建
1.安装前期工作 1).安装Node.js http://nodejs.cn/download/ 里面内置了npm,可以用来安装 Cordova,把该路径添加到环境变量,这样就可以在 cmd 里面任何 ...
- 我的Chrome
插件: CaretTab - New Tab Clock and Date 完全就是为了好看