InstaMaterial概念设计第三部分-feed卡片上的按钮、评论按钮

Home / Android MrLee 2015-2-9 3596

这是今天这篇文章完成之后的最终效果(棒棒糖以及棒棒糖之前):是youtube视频,没法看。暂时连不上。。。

初始化

没有什么大书特书的,我们只需为feed卡片元素中的按钮(喜欢以及评论按钮)加上图标就可以了。这一步的代码提交在这里this commit.完了之后,我们还是不忙着去实现新的东西(新的UI元素),还需要、、、

修正bug以及优化性能

是啊,即便是小如InstaMaterial 这样的demo级应用,你也总能找到提升的空间。

Toolbar theme

首先我们遗漏了Toolbar的样式,这就是为什么menu按钮(Toolbar左边的按钮)的按下颜色是默认的深色。如下:

1423466036139233

(作者的目的是做的和视频一模一样,即便是颜色的深浅,个人认为没必要这么较真是吧) 下载按钮(ToolBar右边的按钮)的按下颜色是浅色的,因为它是使用的带selector的自定义view,selector的定义如下 menu_item_view.xml
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中是这样使用的:
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">
这样Toolbar上的所有元素都将有着继承自Dark.ActionBar主题的样式。 顺便说下,如果你对android主题和样式的定义感兴趣,想知道他们的区别,这篇文章值得一读-Styling Views on Android (Without Going Crazy). 按照上面的做了之后,menu的按下效果看起来就是这个样子了(只在Lollipop 中):

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()之前

1423466285388921

Feed 卡片上的按钮

下面就让我们开始卡片上那些按钮(目前只有喜欢和评论按钮)的工作吧.从视频中的效果来看是非常赞的,圆形扩散的selector

1423466301136892

Android 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
我们项目中实现Ripple的方法是非常简单的:
在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效果。

1423466363422486


注:评论发布按钮对应的类是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 的实现。注:这部分最好根据文中提到的变量名方法名对照代码理解。

设计

和feed中的操作按钮一样,我们需要为SendCommentButton准备两个selector。棒棒糖的设备我们使用ripple效果。pre-21的设备我们制造出标准的按下效果和阴影效果就可以了,就像在第一篇文章中对浮动操作按钮的做法。
下面是两种xml的代码:
res/drawable-v21/btn_send_comment.xml:










res/drawable/btn_send_comment.xml:



    
        
            
                
                    
                    
                
            
 
            
                
                    
                    
                
            
        
    
    
        
            
            
        
    
 


错误振动提示

最后,我们将增加一个视频中没有出现的效果-当发送评论时如果输入框中没有内容,则播放振动动画。下面是效果图:

1423475887174235

Implementation is pretty simple - we have to create shake animation and custom CycleInterpolator for repeating this animation. Everything is in a few lines of code:
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

本文链接:https://www.it72.com/980.htm

推荐阅读
最新回复 (0)
返回