欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Material Design系列之Behavior實現(xiàn)Android知乎首頁

 更新時間:2016年09月12日 14:33:36   作者:yanzhenjie1003  
這篇文章主要為大家詳細(xì)介紹了Material Design系列之Behavior實現(xiàn)Android知乎首頁的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本博客目的:仿知乎首頁向上滑動時動畫隱藏Toolbar、FlocationActionButton、Tab導(dǎo)航,下滑時顯示,如果和你的期望不同,那么你可以不需要看了,免的浪費你的寶貴時間噢。

效果預(yù)覽

知乎效果:

本博客實現(xiàn)效果:


今天效果的源代碼下載鏈接在文章末尾。

實現(xiàn)分析

這個效果其實并不難實現(xiàn),但是它的用處很大,當(dāng)用戶手指上滑,屏幕上顯示下方內(nèi)容的時候,隱藏Toolbar、Tab導(dǎo)航、FAB來騰出更大的空間顯示內(nèi)容,讓用戶爽。簡單粗暴,但這就是我們的目的。

首先就是頭部的Toolbar,這個就不用說了吧,基本會,不會的人隨便看我一篇博客的demo都有這個效果,簡直小學(xué)級別。

其次來看看FAB(FlocationActionButton)的顯示和隱藏,知乎是用的平移,我們這里做個優(yōu)化改動,當(dāng)然平移也是可以的,如果你看過我的Material Design系列,自定義Behavior之上滑顯示返回頂部按鈕這篇博客的話。那么我們的FAB的動畫隱藏和顯示也是用上一篇博客的原理,沒有看上一篇博客的同學(xué)需要回過頭看看噢,這里不在贅述。

最后來看下面的Tab導(dǎo)航的隱藏和顯示,這個確確實實用平移更好是吧,然而相信你如果看過我Material Design系列,Behavior之BottomSheetBehavior與BottomSheetDialog這篇博客的話,這個效果實現(xiàn)起來也不難。強烈建議看下文之前讀這篇文章,不然真的沒法繼續(xù)看下去了。

其實代碼量還是很少的,主要是Behavior原理、Behavior和CoordinatorLayout如何結(jié)合使用。so,強烈建議去上讀下上面兩篇博客噢。

……

好的,五分鐘過去了,我相信你大概已經(jīng)速讀了上面提到的兩篇博客了。那么在第一篇FAB的那篇博客中實現(xiàn)的效果是手指向上滑時(屏幕顯示下方的內(nèi)容時)顯示FAB用來回到頂部,但是這里剛好是相反的:向上滑時隱藏FAB。如果你認(rèn)真讀了原理解釋的那一段或者運行過demo,這個效果so easy吧。第二篇博客中也講到了如何隱藏和顯示這個Tab導(dǎo)航,那么有的同學(xué)就覺得今天的博客就結(jié)束了吧?答案當(dāng)然是No了,不然我也不會再開一篇博客來講這個了。

為什么呢?還是有難點的,難點在哪里?就是上面講到的兩個Behavior如何和CoordinatorLayout結(jié)合使用,同時實現(xiàn)兩個效果。而且BottomSheetBehavior隱藏和顯示Tab導(dǎo)航這個里面之前我們使用Button來控制的,如何做到`CoordinatorLayout中的ContentView滑動時動態(tài)的顯示和隱藏Tab導(dǎo)航呢?

接下來來點真材實料,帶領(lǐng)大家一起代碼擼起來。

頁面布局

上面的引文和介紹,我們已經(jīng)知道了FAB的顯示和隱藏用自定義Behavior實現(xiàn),Tab導(dǎo)航用BottomSheetBehavior來實現(xiàn),那么我們布局文件也該問世了:

<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>

還是稍微解釋下,內(nèi)容區(qū)域是一個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需要我們自定義,那么下面我們就來實現(xiàn)下ScaleDownShowBehavior。

自定義Behavior實現(xiàn)FAB的動畫控制

這里又談到了自定義Behavior了,首先就來實現(xiàn):用戶手指在屏幕上滑,隱藏FAB,留出更多位置給用戶。

這里還是繼承FloatingActionButton.Behavior:

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

這里我們的滑動方向還是不變,監(jiān)聽豎著方向的滑動:

@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, ...) {
 return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}

那么我們就要稍微改一下我們的開始滑動時回調(diào)這個方法了:onNestedScroll():

@Override
// 隱藏動畫是否正在執(zhí)行
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:

復(fù)制代碼 代碼如下:
<string name="scale_down_show_behavior">com.yanzhenjie.definebehavior.behavior.ScaleDownShowBehavior</string>

啊呀,好激動呀,我趕緊運行一下。但是但是。。。運行后發(fā)現(xiàn)見鬼啊,只有FAB會跟著顯示和隱藏,完全看不到Tab導(dǎo)航呀,嚴(yán)振杰你是在忽悠人麼?哈哈哈哈,且聽我細(xì)細(xì)道來。

通過監(jiān)聽ScaleDownShowBehavior中的view顯示/隱藏來控制Tab導(dǎo)航欄

其實只要看過Material Design系列,Behavior之BottomSheetBehavior與BottomSheetDialog這篇文章的同學(xué)會發(fā)現(xiàn),用BottomSheetBehavior的控件默認(rèn)都是隱藏起來的,需要我們?nèi)フ{(diào)用它的方法來控制它的View的顯示。所以我們這里需要在CoordinatorLayout中的ContentView滾動的時候來調(diào)用BottomSheetBehavior的方法使它依附的View顯示與隱藏。

那么我們發(fā)現(xiàn)ScaleDownShowBehavior被系統(tǒng)自動調(diào)用了,也觸發(fā)了View的隱藏和顯示,CoordinatorLayout這貨沒有給我們自動調(diào)用BottomSheetBehavior,我們怎么辦?如果你沒有忘記的話,我們自定義ScaleDownShowBehavior的時候,在onNestedScroll()方法中有個地方是去調(diào)用了FAB的顯示和隱藏,所以我們在這里加一個回調(diào)監(jiān)聽,讓外部可以監(jiān)聽到它的動作,是不是同時可以控制BottomSheetBehavior了?如果還沒有向明的話看代碼。

先在ScaleDownShowBehavior中定一個Listener:

// 外部監(jiān)聽顯示和隱藏。
public interface OnStateChangedListener {
 void onChanged(boolean isShow);
}

然后在ScaleDownShowBehavior的onNestedScroll()方法中回調(diào):

private OnStateChangedListener mOnStateChangedListener;

public void setOnStateChangedListener(OnStateChangedListener mOnStateChangedListener) {
 this.mOnStateChangedListener = mOnStateChangedListener;
}

@Override
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) {//往下滑
  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);
  }
 }
}

好完美啊。來來來,設(shè)置一個監(jiān)聽。。。我勒個去,突然發(fā)現(xiàn)怎么從FAB拿到這個Behavior???且看我下面的分析,保證讓你柳暗花明又一村啊。

拿到FAB的Behavior對象,通過監(jiān)聽控制BottomSheetBehavior的View的顯示/隱藏

我們這知道,給一個View設(shè)置Behavior對象的時候是在xml中設(shè)置,所以Behavior是一個View的LayoutParams屬性吧?哈哈哈明白了吧,然后Behavior又必須和CoordinatorLayout結(jié)合使用,不然也是扯淡,so,這個View也必須是CoordinatorLayout的子View,所以在ScaleDownShowBehavior中產(chǎn)生了如下的一個靜態(tài)方法(為了方便閱讀,提示寫了中文):

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;
@Override
protected 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);
 }
};

哎喲喂,不知不覺中已經(jīng)把我們的效果實現(xiàn)了,這里最重要的就是onStateChangedListener了,這里實現(xiàn)了Tab導(dǎo)航的隱藏和顯示,它的狀態(tài)是從ScaleDownShowBehavior中回調(diào)出來的。

頁面初始化好后顯示Tab導(dǎo)航

我們上文中說道,添加了BottomSheetBehavior屬性的View,默認(rèn)是隱藏的,所以我們在頁面初始化時要把我們的Tab導(dǎo)航顯示出來:

private boolean initialize = false;

@Override
public 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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論