Material Design系列之Behavior实现Android知乎首页

Material Design系列之Behavior实现Android知乎首页,第1张

概述本博客目的:仿知乎首页向上滑动时动画隐藏Toolbar、FlocationActionButton、Tab导航,下滑时显示,如果和你的期望不同,那么你可以不需要看了,免的浪费你的宝贵时间噢。

本博客目的:仿知乎首页向上滑动时动画隐藏Toolbar、FlocationActionbutton、Tab导航,下滑时显示,如果和你的期望不同,那么你可以不需要看了,免的浪费你的宝贵时间噢。

效果预览

知乎效果:

本博客实现效果:


今天效果的源代码下载链接在文章末尾。

实现分析

这个效果其实并不难实现,但是它的用处很大,当用户手指上滑,屏幕上显示下方内容的时候,隐藏Toolbar、Tab导航、FAB来腾出更大的空间显示内容,让用户爽。简单粗暴,但这就是我们的目的。

首先就是头部的Toolbar,这个就不用说了吧,基本会,不会的人随便看我一篇博客的demo都有这个效果,简直小学级别。

其次来看看FAB(FlocationActionbutton)的显示和隐藏,知乎是用的平移,我们这里做个优化改动,当然平移也是可以的,如果你看过我的Material Design系列,自定义Behavior之上滑显示返回顶部按钮这篇博客的话。那么我们的FAB的动画隐藏和显示也是用上一篇博客的原理,没有看上一篇博客的同学需要回过头看看噢,这里不在赘述。

最后来看下面的Tab导航的隐藏和显示,这个确确实实用平移更好是吧,然而相信你如果看过我Material Design系列,Behavior之BottomSheetBehavior与BottomSheetDialog这篇博客的话,这个效果实现起来也不难。强烈建议看下文之前读这篇文章,不然真的没法继续看下去了。

其实代码量还是很少的,主要是Behavior原理、Behavior和CoordinatorLayout如何结合使用。so,强烈建议去上读下上面两篇博客噢。

……

好的,五分钟过去了,我相信你大概已经速读了上面提到的两篇博客了。那么在第一篇FAB的那篇博客中实现的效果是手指向上滑时(屏幕显示下方的内容时)显示FAB用来回到顶部,但是这里刚好是相反的:向上滑时隐藏FAB。如果你认真读了原理解释的那一段或者运行过demo,这个效果so easy吧。第二篇博客中也讲到了如何隐藏和显示这个Tab导航,那么有的同学就觉得今天的博客就结束了吧?答案当然是No了,不然我也不会再开一篇博客来讲这个了。

为什么呢?还是有难点的,难点在哪里?就是上面讲到的两个Behavior如何和CoordinatorLayout结合使用,同时实现两个效果。而且BottomSheetBehavior隐藏和显示Tab导航这个里面之前我们使用button来控制的,如何做到`CoordinatorLayout中的ContentVIEw滑动时动态的显示和隐藏Tab导航呢?

接下来来点真材实料,带领大家一起代码撸起来。

页面布局

上面的引文和介绍,我们已经知道了FAB的显示和隐藏用自定义Behavior实现,Tab导航用BottomSheetBehavior来实现,那么我们布局文件也该问世了:

<androID.support.design.Widget.CoordinatorLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:app="http://schemas.androID.com/apk/res-auto" androID:layout_wIDth="match_parent" androID:layout_height="match_parent"> <androID.support.design.Widget.AppbarLayout  androID:layout_wIDth="match_parent"  androID:layout_height="wrap_content"  androID:theme="@style/Apptheme.AppbarOverlay">  <androID.support.v7.Widget.Toolbar   androID:ID="@+ID/toolbar"   androID:layout_wIDth="match_parent"   androID:layout_height="?attr/actionbarSize"   app:layout_scrollFlags="scroll|enteralways|snap"   app:popuptheme="@style/Apptheme.PopupOverlay" /> </androID.support.design.Widget.AppbarLayout> <androID.support.v7.Widget.RecyclerVIEw  androID:ID="@+ID/recyclerVIEw"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  app:layout_behavior="@string/appbar_scrolling_vIEw_behavior" /> <linearLayout  androID:ID="@+ID/tab_layout"  androID:layout_wIDth="match_parent"  androID:layout_height="?actionbarSize"  androID:layout_alignParentBottom="true"  androID:background="@androID:color/white"  app:layout_behavior="@string/bottom_sheet_behavior">  <button   androID:layout_wIDth="0dp"   androID:layout_height="match_parent"   androID:layout_weight="1"   androID:text="第一" />  <button   androID:layout_wIDth="0dp"   androID:layout_height="match_parent"   androID:layout_weight="1"   androID:text="第二" />  <button   androID:layout_wIDth="0dp"   androID:layout_height="match_parent"   androID:layout_weight="1"   androID:text="第三" />  <button   androID:layout_wIDth="0dp"   androID:layout_height="match_parent"   androID:layout_weight="1"   androID:text="第四" /> </linearLayout> <androID.support.design.Widget.floatingActionbutton  androID:ID="@+ID/fab"  androID:layout_wIDth="wrap_content"  androID:layout_height="wrap_content"  androID:layout_gravity="bottom|end"  androID:layout_marginBottom="70dp"  androID:layout_marginEnd="16dp"  androID:layout_marginRight="16dp"  androID:src="@mipmap/ic_action_new"  app:layout_behavior="@string/scale_down_show_behavior"  app:layout_scrollFlags="scroll|enteralways|snap" /></androID.support.design.Widget.CoordinatorLayout>

还是稍微解释下,内容区域是一个RecyclerVIEw,使用的Behavior是design的ScrollingVIEwBehavior:

app:layout_behavior="@string/appbar_scrolling_vIEw_behavior"

然后一个linearLayout,使用的Behavior是design的BottomSheetBehavior:

app:layout_behavior="@string/bottom_sheet_behavior"

最后一个floatingActionbutton,使用我们的自定义ScaleDownShowBehavior:

app:layout_behavior="@string/scale_down_show_behavior"

其他两个都是design自带的,唯有floatingActionbutton的ScaleDownShowBehavior需要我们自定义,那么下面我们就来实现下ScaleDownShowBehavior。

自定义Behavior实现FAB的动画控制

这里又谈到了自定义Behavior了,首先就来实现:用户手指在屏幕上滑,隐藏FAB,留出更多位置给用户。

这里还是继承floatingActionbutton.Behavior:

public class ScaleDownShowBehavior extends floatingActionbutton.Behavior { public ScaleDownShowBehavior(Context context,AttributeSet attrs) {  super(); }}

这里我们的滑动方向还是不变,监听竖着方向的滑动:

@OverrIDepublic boolean onStartnestedScroll(CoordinatorLayout coordinatorLayout,...) { return nestedScrollAxes == VIEwCompat.SCRolL_AXIS_VERTICAL;}

那么我们就要稍微改一下我们的开始滑动时回调这个方法了:onnestedScroll():

@OverrIDe// 隐藏动画是否正在执行private boolean isAnimatingOut = false;public voID onnestedScroll(CoordinatorLayout coordinatorLayout,floatingActionbutton child,VIEw target,int dxconsumed,int dyConsumed,int dxUnconsumed,int dyUnconsumed) { if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimatingOut && child.getVisibility() == VIEw.VISIBLE) {// 手指上滑,隐藏FAB  AnimatorUtil.scaleHIDe(child,Listener); } else if ((dyConsumed < 0 || dyUnconsumed < 0) && child.getVisibility() != VIEw.VISIBLE) {  AnimatorUtil.scaleShow(child,null);// 手指下滑,显示FAB }}private VIEwPropertyAnimatorListener Listener = new VIEwPropertyAnimatorListener() { @OverrIDe public voID onAnimationStart(VIEw vIEw) {  isAnimatingOut = true; } @OverrIDe public voID onAnimationEnd(VIEw vIEw) {  isAnimatingOut = false;  vIEw.setVisibility(VIEw.GONE); } @OverrIDe public voID onAnimationCancel(VIEw arg0) {  isAnimatingOut = false; }};

好吧,代码非常少,完成了。那么我们就在string.xml中定义好,刚才我们引用的变量@string/scale_down_show_behavior:

复制代码 代码如下:<string name="scale_down_show_behavior">com.yanzhenjIE.definebehavior.behavior.ScaleDownShowBehavior</string>

啊呀,好激动呀,我赶紧运行一下。但是但是。。。运行后发现见鬼啊,只有FAB会跟着显示和隐藏,完全看不到Tab导航呀,严振杰你是在忽悠人麽?哈哈哈哈,且听我细细道来。

通过监听ScaleDownShowBehavior中的vIEw显示/隐藏来控制Tab导航栏

其实只要看过Material Design系列,Behavior之BottomSheetBehavior与BottomSheetDialog这篇文章的同学会发现,用BottomSheetBehavior的控件默认都是隐藏起来的,需要我们去调用它的方法来控制它的VIEw的显示。所以我们这里需要在CoordinatorLayout中的ContentVIEw滚动的时候来调用BottomSheetBehavior的方法使它依附的VIEw显示与隐藏。

那么我们发现ScaleDownShowBehavior被系统自动调用了,也触发了VIEw的隐藏和显示,CoordinatorLayout这货没有给我们自动调用BottomSheetBehavior,我们怎么办?如果你没有忘记的话,我们自定义ScaleDownShowBehavior的时候,在onnestedScroll()方法中有个地方是去调用了FAB的显示和隐藏,所以我们在这里加一个回调监听,让外部可以监听到它的动作,是不是同时可以控制BottomSheetBehavior了?如果还没有向明的话看代码。

先在ScaleDownShowBehavior中定一个Listener:

// 外部监听显示和隐藏。public interface OnStateChangedListener { voID onChanged(boolean isShow);}

然后在ScaleDownShowBehavior的onnestedScroll()方法中回调:

private OnStateChangedListener mOnStateChangedListener;public voID setonStateChangedListener(OnStateChangedListener mOnStateChangedListener) { this.mOnStateChangedListener = mOnStateChangedListener;}@OverrIDepublic voID onnestedScroll(CoordinatorLayout coordinatorLayout,int dyUnconsumed) { if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimatingOut && child.getVisibility() == VIEw.VISIBLE) {//往下滑  AnimatorUtil.scaleHIDe(child,vIEwPropertyAnimatorListener);  if (mOnStateChangedListener != null) {   mOnStateChangedListener.onChanged(false);  } } else if ((dyConsumed < 0 || dyUnconsumed < 0) && child.getVisibility() != VIEw.VISIBLE) {  AnimatorUtil.scaleShow(child,null);  if (mOnStateChangedListener != null) {   mOnStateChangedListener.onChanged(true);  } }}

好完美啊。来来来,设置一个监听。。。我勒个去,突然发现怎么从FAB拿到这个Behavior啊?且看我下面的分析,保证让你柳暗花明又一村啊。

拿到FAB的Behavior对象,通过监听控制BottomSheetBehavior的VIEw的显示/隐藏

我们这知道,给一个VIEw设置Behavior对象的时候是在xml中设置,所以Behavior是一个VIEw的LayoutParams属性吧?哈哈哈明白了吧,然后Behavior又必须和CoordinatorLayout结合使用,不然也是扯淡,so,这个VIEw也必须是CoordinatorLayout的子VIEw,所以在ScaleDownShowBehavior中产生了如下的一个静态方法(为了方便阅读,提示写了中文):

public static <V extends VIEw> ScaleDownShowBehavior from(V vIEw) { VIEwGroup.LayoutParams params = vIEw.getLayoutParams(); if (!(params instanceof CoordinatorLayout.LayoutParams)) {  throw new IllegalArgumentException("这个VIEw不是CoordinatorLayout的子VIEw"); } CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior(); if (!(behavior instanceof ScaleDownShowBehavior)) {  throw new IllegalArgumentException("这个VIEw的Behaviro不是ScaleDownShowBehavior"); } return (ScaleDownShowBehavior) behavior;}

所以我们在Activity中:

private BottomSheetBehavior mBottomSheetBehavior;@OverrIDeprotected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.zhihu_main); ScaleDownShowBehavior scaleDownShowFab = ScaleDownShowBehavior.from(FAB); scaleDownShowFab.setonStateChangedListener(onStateChangedListener); mBottomSheetBehavior = BottomSheetBehavior.from(findVIEwByID(R.ID.tab_layout));}private OnStateChangedListener onStateChangedListener = new OnStateChangedListener() { @OverrIDe public voID onChanged(boolean isShow) {  mBottomSheetBehavior.setState(  isShow ? BottomSheetBehavior.STATE_EXPANDED  : BottomSheetBehavior.STATE_ColLAPSED); }};

哎哟喂,不知不觉中已经把我们的效果实现了,这里最重要的就是onStateChangedListener了,这里实现了Tab导航的隐藏和显示,它的状态是从ScaleDownShowBehavior中回调出来的。

页面初始化好后显示Tab导航

我们上文中说道,添加了BottomSheetBehavior属性的VIEw,默认是隐藏的,所以我们在页面初始化时要把我们的Tab导航显示出来:

private boolean initialize = false;@OverrIDepublic voID onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (!initialize) {  initialize = true;  mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }}

源码下载:http://xiazai.jb51.net/201609/yuanma/AndroidBehavior(jb51.net).rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Material Design系列之Behavior实现Android知乎首页全部内容,希望文章能够帮你解决Material Design系列之Behavior实现Android知乎首页所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1148300.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存