这是今天这篇文章完成之后的最终效果(棒棒糖以及棒棒糖之前):是youtube视频,没法看。暂时连不上。。。
这个机制在我们这里会导致一个问题,启动应用之后,在屏幕可见范围内,我们只有一张卡片可见(估计作者的屏幕比较小),当我们滚动的时候,RecyclerView找不到可以重用的view了,它将创建一个新的,因此在滑动到第二个feed的时候就会有一定的延时,但是第二个feed之后的滚动是流畅的,因为这个时候RecyclerView已经有能重用的view了。
下面是实际效果: 在重写getExtraLayoutSpace()之前
在feed_item.xml中将下面的drawable作为按钮的背景
res/drawable-v21/btn_feed_action.xml
我当然知道可以使用诸如mimic ripple effect 这样的库来兼容老设备,但是没有一个库达到了该有的效果。它们需要添加额外的代码(比如添加额外的布局来包裹),在Lollipop版本上无法使用原生的Ripple 效果,性能问题等等。
But why is so hard to copy Ripple effect into pre-21 Android?
但是为什么在pre-21的设备上复制Ripple 效果会这么难呢?
随着app的布局日益复杂,UI需要更多的时间去绘制、测量。现在问题来了,如果我们的动画执行到一半,而开启了另外一个UI任务(比如为新的activity inflat布局),但是只有一个UI线程,那么动画将被停止。
Lollipop中所引入的Render线程将解决这个问题。Render线程通过将渲染分成两部分来解决,简单的来说就是:我们有一个被UI线程创建的动画单元的列表,这些动画将被甩到独立的render线程当中。因此在执行开销较大的UI操作的时候,动画也能继续下去。
这就是ripple效果的工作原理。他们是在render线程中执行的。所以不会被打开新的activity这样的操作打断。
所以没法在pre-21的安卓系统上完全实现ripple效果。
res/drawable/btn_feed_action.xml:
注:评论发布按钮对应的类是SendCommentButton.java,这一节中讲解的内容都是在这个类中。结合代码更容易看明白。
关于这个按钮SendCommentButton,我将用到下面几个android元素:
ViewAnimator:作为SendCommentButton的基类,它有一个对我们非常有用的特性,可以设置子view切换时的进入和退出效果。如果你对ViewAnimator很陌生,其直接子类ViewFlipper, ViewSwitcher或间接子类ImageSwitcher, TextSwitcher应该很熟悉。
自定义view:包括xml以及inflate xml的代码
标签消除冗余的view
发送状态:
滑出顶端
从顶端滑入
完成状态:
从底部滑入
滑出底部
现在来实现button的布局:
因为ViewAnimator本身是一个FrameLayout,因此需要使用标签来减少了一层view。
最后,我们只有一个需求了,当button切换到完成状态之后,隔两秒它会自动切换回去。
代码很简单:
init()方法(29行)将前面创建的布局inflate给了ViewAnimator。顺便可以去看下这篇文章proper Layout Inflation,里面讲解了些很可能被你忽略的细节。
为了防止在activity结束的时候按钮的状态还没有切换回来,onDetachedFromWindow()去掉了回调方法revertStateRunnable()。
其余的都非常简单,通过setInAnimation() and setOutAnimation()两个方法来实现进入和退出动画。
好了,刚刚我们完成了SendCommentButton 的实现。注:这部分最好根据文中提到的变量名方法名对照代码理解。
下面是两种xml的代码:
res/drawable-v21/btn_send_comment.xml:
res/drawable/btn_send_comment.xml:
res/anim/shake_error.xml:
实现很简单-创建一个振动动画并使用自定义的CycleInterpolator插值器来重复播放这个动画,只有几行代码:
res/anim/cycle_2.xml:
通过如下的代码来将这个动画应用到按钮中: btnSendComment.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake_error)); 这就是今天所讲的全部内容了,这里是含有SendCommentButton类的最后一次提交:last commit 。下篇文章中我们将继续实现概念视频中的效果.
源码下载:repository.
本文原出处:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0209/2451.html
初始化
没有什么大书特书的,我们只需为feed卡片元素中的按钮(喜欢以及评论按钮)加上图标就可以了。这一步的代码提交在这里this commit.完了之后,我们还是不忙着去实现新的东西(新的UI元素),还需要、、、修正bug以及优化性能
是啊,即便是小如InstaMaterial 这样的demo级应用,你也总能找到提升的空间。Toolbar theme
首先我们遗漏了Toolbar的样式,这就是为什么menu按钮(Toolbar左边的按钮)的按下颜色是默认的深色。如下:android:background="@drawable/btn_default_light"但是这只在Lollipop上有效果(这里翻译可能有误,原文是This inconsistency appears only in Android Lollipop ),解决的办法很简单。只需在activity_comments.xml 和activity_main.xml的ToolBar控件中加上一行代码:
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"注:在toolbar中是这样使用的:
这样Toolbar上的所有元素都将有着继承自Dark.ActionBar主题的样式。 顺便说下,如果你对android主题和样式的定义感兴趣,想知道他们的区别,这篇文章值得一读-Styling Views on Android (Without Going Crazy). 按照上面的做了之后,menu的按下效果看起来就是这个样子了(只在Lollipop 中):layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="@dimen/default_elevation" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
RecyclerView 元素的预加载
另一个问题是在app启动之后feed列表的滚动不太顺滑。几乎每次在滚到第二个卡片的时候都有卡顿。幸好,造成这个问题的原因简单。RecyclerView (以及其他基于adapter的view,比如ListView、GridView等)使用了缓存机制重用子view(简而言之就是,系统只将屏幕可见范围之内的元素保存在内存中,在滚动的时候不断的重用这些内存中已经存在的view,而不是新建view)。这个机制在我们这里会导致一个问题,启动应用之后,在屏幕可见范围内,我们只有一张卡片可见(估计作者的屏幕比较小),当我们滚动的时候,RecyclerView找不到可以重用的view了,它将创建一个新的,因此在滑动到第二个feed的时候就会有一定的延时,但是第二个feed之后的滚动是流畅的,因为这个时候RecyclerView已经有能重用的view了。
如何解决这个问题?
好在本例使用的是LinearLayoutManager ,因此很简单。只需重写getExtraLayoutSpace()方法。根据官方文档的描述getExtraLayoutSpace将返回LayoutManager应该预留的额外空间(显示范围之外,应该额外缓存的空间)。LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) { @Override protected int getExtraLayoutSpace(RecyclerView.State state) { return 300; } };
下面是实际效果: 在重写getExtraLayoutSpace()之前
Feed 卡片上的按钮
下面就让我们开始卡片上那些按钮(目前只有喜欢和评论按钮)的工作吧.从视频中的效果来看是非常赞的,圆形扩散的selectorAndroid Lollipop中的Ripple效果
按钮所使用的Selector无非就是棒棒糖中介绍的Ripple效果-一种水波扩散效果。已经有无数关于Ripple效果的文章,这里就不赘述了,我只给出两篇文章的链接:- Ripples – Part 1 and Ripples – Part 2 from Styling Android blog
- Implementing Material Design in Your Android app from official Android Developers Blog
在feed_item.xml中将下面的drawable作为按钮的背景
res/drawable-v21/btn_feed_action.xml
不要在L之前的设备上使用ripples效果
我承诺过我将实现概念视频中的所有效果,但是有时候,去做一件达不到预期的事情,还不如不做。在pre-21的设备上实现ripple就是一件达不到预期的事情。我当然知道可以使用诸如mimic ripple effect 这样的库来兼容老设备,但是没有一个库达到了该有的效果。它们需要添加额外的代码(比如添加额外的布局来包裹),在Lollipop版本上无法使用原生的Ripple 效果,性能问题等等。
But why is so hard to copy Ripple effect into pre-21 Android?
但是为什么在pre-21的设备上复制Ripple 效果会这么难呢?
Ripple揭秘
在棒棒糖版本之前,整个UI都是在UI主线程中管理的。几乎每个人都知道ANR对话框,NetworkOnMainThreadException,我们也是知道“不要将耗时操作放在UI线程中,仅仅在UI线程中显示操作结果”这条黄金定律。一切都看似可行,除了那句“整个UI都是被UI主线程所管理的”。随着app的布局日益复杂,UI需要更多的时间去绘制、测量。现在问题来了,如果我们的动画执行到一半,而开启了另外一个UI任务(比如为新的activity inflat布局),但是只有一个UI线程,那么动画将被停止。
Lollipop中所引入的Render线程将解决这个问题。Render线程通过将渲染分成两部分来解决,简单的来说就是:我们有一个被UI线程创建的动画单元的列表,这些动画将被甩到独立的render线程当中。因此在执行开销较大的UI操作的时候,动画也能继续下去。
这就是ripple效果的工作原理。他们是在render线程中执行的。所以不会被打开新的activity这样的操作打断。
所以没法在pre-21的安卓系统上完全实现ripple效果。
老版本上的兼容“ripple”效果
因为不能在pre-21上实现ripple,那么我们就实现类似的效果就可以了。我们创建了一个带进入退出渐变的圆形的selector,尽管没有ripple那么花哨,但是看起来还是可以.res/drawable/btn_feed_action.xml:
评论发布按钮
评论发布按钮非常有趣。正如你在视频中看到的,按钮可以在两个状态之间做简单的动画切换,并且点击的时候有ripple效果。注:评论发布按钮对应的类是SendCommentButton.java,这一节中讲解的内容都是在这个类中。结合代码更容易看明白。
关于这个按钮SendCommentButton,我将用到下面几个android元素:
ViewAnimator:作为SendCommentButton的基类,它有一个对我们非常有用的特性,可以设置子view切换时的进入和退出效果。如果你对ViewAnimator很陌生,其直接子类ViewFlipper, ViewSwitcher或间接子类ImageSwitcher, TextSwitcher应该很熟悉。
自定义view:包括xml以及inflate xml的代码
实现
好了,现在来开始实现,从动画开始。实际上我们需要四个动画,发送状态两个(进入和退出),完成状态两个(进入和退出,不过是相反的方向):发送状态:
滑出顶端
从顶端滑入
完成状态:
从底部滑入
滑出底部
现在来实现button的布局:
因为ViewAnimator本身是一个FrameLayout,因此需要使用
最后,我们只有一个需求了,当button切换到完成状态之后,隔两秒它会自动切换回去。
代码很简单:
init()方法(29行)将前面创建的布局inflate给了ViewAnimator。顺便可以去看下这篇文章proper Layout Inflation,里面讲解了些很可能被你忽略的细节。
为了防止在activity结束的时候按钮的状态还没有切换回来,onDetachedFromWindow()去掉了回调方法revertStateRunnable()。
其余的都非常简单,通过setInAnimation() and setOutAnimation()两个方法来实现进入和退出动画。
好了,刚刚我们完成了SendCommentButton 的实现。注:这部分最好根据文中提到的变量名方法名对照代码理解。
设计
和feed中的操作按钮一样,我们需要为SendCommentButton准备两个selector。棒棒糖的设备我们使用ripple效果。pre-21的设备我们制造出标准的按下效果和阴影效果就可以了,就像在第一篇文章中对浮动操作按钮的做法。下面是两种xml的代码:
res/drawable-v21/btn_send_comment.xml:
res/drawable/btn_send_comment.xml:
错误振动提示
最后,我们将增加一个视频中没有出现的效果-当发送评论时如果输入框中没有内容,则播放振动动画。下面是效果图:res/anim/shake_error.xml:
实现很简单-创建一个振动动画并使用自定义的CycleInterpolator插值器来重复播放这个动画,只有几行代码:
res/anim/cycle_2.xml:
xml version="1.0" encoding="utf-8"?>
通过如下的代码来将这个动画应用到按钮中: btnSendComment.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake_error)); 这就是今天所讲的全部内容了,这里是含有SendCommentButton类的最后一次提交:last commit 。下篇文章中我们将继续实现概念视频中的效果.
源码下载:repository.
本文原出处:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0209/2451.html
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2305
- 用户1336
- 访客11455848
每日一句
Talent without working hard is nothing.
没有努力,天份不代表什么。
没有努力,天份不代表什么。
MySQL 数据库优化
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
免ROOT实现模拟点击任意位置
Mobaxterm终端神器
CreateProcessW要注意的细节问题
Autonomous NAT Traversal
【教程】win10 彻底卸载edge浏览器
eclipse工程基于Xposed的一个简单Hook
排名前5的开源在线机器学习
Mac OS最简单及(Karabiner)快捷键设置
发一款C++编写的麻将
VMware NAT端口映射外网访问虚拟机linux
独家发布最新可用My-AutoPost——wordpress 采集器
新会员