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

Android嵌套滾動(dòng)NestedScroll的實(shí)現(xiàn)了解一下

 更新時(shí)間:2018年06月05日 14:29:42   作者:林嘉偉  
嵌套滾動(dòng)已經(jīng)算一個(gè)比較常見(jiàn)的特效了,這篇文章主要介紹了Android嵌套滾動(dòng)NestedScroll的實(shí)現(xiàn)了解一下,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

其實(shí)嵌套滾動(dòng)已經(jīng)算一個(gè)比較常見(jiàn)的特效了,下面這個(gè)動(dòng)圖就是嵌套滾動(dòng)的一個(gè)例子:

看到這個(gè)動(dòng)效,大家可能都知道可以用CoordinatorLayout去實(shí)現(xiàn).其實(shí)CoordinatorLayout是基于NestedScroll機(jī)制去實(shí)現(xiàn)的,而我們直接通過(guò)NestedScroll機(jī)制也能很方便的實(shí)現(xiàn)這個(gè)動(dòng)效.

原理

NestedScroll的其實(shí)很簡(jiǎn)單.

一般的觸摸消息的分發(fā)都是從外向內(nèi)的,由外層的ViewGroup的dispatchTouchEvent方法調(diào)用到內(nèi)層的View的dispatchTouchEvent方法.

而NestedScroll提供了一個(gè)反向的機(jī)制,內(nèi)層的view在接收到ACTION_MOVE的時(shí)候,將滾動(dòng)消息先傳回給外層的ViewGroup,看外層的ViewGroup是不是需要消耗一部分的移動(dòng),然后內(nèi)層的View再去消耗剩下的移動(dòng).內(nèi)層view可以消耗剩下的滾動(dòng)的一部分,如果還沒(méi)有消耗完,外層的view可以再選擇把最后剩下的滾動(dòng)消耗掉.

上面的描述可能有點(diǎn)繞,可以看下面的圖來(lái)幫助理解:

 

具體實(shí)現(xiàn)

NestedScroll機(jī)制會(huì)涉及到四個(gè)類:

NestedScrollingChild, NestedScrollingChildHelper 和 NestedScrollingParent , NestedScrollingParentHelper

NestedScrollingChild和NestedScrollingParent是兩個(gè)接口,我們先看看他們的聲明:

public interface NestedScrollingChild {
  public void setNestedScrollingEnabled(boolean enabled);

  public boolean isNestedScrollingEnabled();

  public boolean startNestedScroll(int axes);

  public void stopNestedScroll();

  public boolean hasNestedScrollingParent();

  public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
      int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);

  public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);

  public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);

  public boolean dispatchNestedPreFling(float velocityX, float velocityY);
}

public interface NestedScrollingParent {
  public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);

  public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);

  public void onStopNestedScroll(View target);

  public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
      int dxUnconsumed, int dyUnconsumed);

  public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);

  public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);

  public boolean onNestedPreFling(View target, float velocityX, float velocityY);

  public int getNestedScrollAxes();
}

這里真正重要的其實(shí)是NestedScrollingParent的幾個(gè)方法,因?yàn)槠渌椒ǘ寄苤苯幼孨estedScrollingChildHelper或者NestedScrollingParentHelper去代理:

  1. onStartNestedScroll 是否接受嵌套滾動(dòng),只有它返回true,后面的其他方法才會(huì)被調(diào)用
  2. onNestedPreScroll 在內(nèi)層view處理滾動(dòng)事件前先被調(diào)用,可以讓外層view先消耗部分滾動(dòng)
  3. onNestedScroll 在內(nèi)層view將剩下的滾動(dòng)消耗完之后調(diào)用,可以在這里處理最后剩下的滾動(dòng)
  4. onNestedPreFling 在內(nèi)層view的Fling事件處理之前被調(diào)用
  5. onNestedFling 在內(nèi)層view的Fling事件處理完之后調(diào)用

我們只要讓子view和父view分別實(shí)現(xiàn)NestedScrollingChild和NestedScrollingParent接口,然后分別調(diào)用NestedScrollingChildHelper和NestedScrollingParentHelper的對(duì)應(yīng)方法去代理一些具體功能,然后在NestedScrollingChild的onTouchEvent那里根據(jù)需求調(diào)用startNestedScroll/dispatchNestedPreScroll/stopNestedScroll就能實(shí)現(xiàn)嵌套滾動(dòng)了:

//NestedScrollingChild
private NestedScrollingChildHelper mHelper = new NestedScrollingChildHelper(this);

public boolean startNestedScroll(int axes) {
 return mHelper.startNestedScroll(axes);
}
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
      int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
 return mHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
       dxUnconsumed, dyUnconsumed, offsetInWindow);
}
...
//NestedScrollingParent
private NestedScrollingParentHelper mHelper = new NestedScrollingParentHelper(this);

public void onNestedScrollAccepted(View child, View target, int axes) {
 mHelper.onNestedScrollAccepted(child, target, axes);
}

public int getNestedScrollAxes() {
 return mHelper.getNestedScrollAxes();
}
...

但是如果你使用sdk21及以上的版本,NestedScroll機(jī)制已經(jīng)直接集成到了View中了,你只需要直接重寫(xiě)View的對(duì)應(yīng)方法就好

布局

我們先看布局文件

<me.linjw.nestedscrolldemo.NestedScrollParentView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <FrameLayout
    android:id="@+id/header"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
      android:layout_width="match_parent"
      android:layout_height="200dp"
      android:src="@mipmap/ic_launcher" />
  </FrameLayout>

  <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorAccent"
    android:text="Title"
    android:textAlignment="center"
    android:textSize="20dp" />

  <android.support.v7.widget.RecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</me.linjw.nestedscrolldemo.NestedScrollParentView>

最外層是我們自定義的NestedScrollParentView,其實(shí)它是一個(gè)LinearLayout,內(nèi)部豎直排列了三個(gè)子view:

  1. 一個(gè)由FrameLayout包裹的ImageView
  2. 一個(gè)TextView
  3. 一個(gè)RecyclerView

代碼

為了簡(jiǎn)便起見(jiàn),我們先直接用sdk22的版本用重寫(xiě)View方法的方式去實(shí)現(xiàn)它.

NestedScrollParentView中有兩個(gè)方法比較重要,嵌套滾動(dòng)基本上就是由這兩個(gè)方法實(shí)現(xiàn)的:

@Override
 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
   return true;
 }

 @Override
 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
   super.onNestedPreScroll(target, dx, dy, consumed);

   boolean headerScrollUp = dy > 0 && getScrollY() < mHeaderHeight;
   boolean headerScrollDown = dy < 0 && getScrollY() > 0 && !target.canScrollVertically(-1);
   if (headerScrollUp || headerScrollDown) {
     scrollBy(0, dy);
     consumed[1] = dy;
   }
 }

onStartNestedScroll 這個(gè)方法如果返回true的話代表接受由內(nèi)層傳來(lái)的滾動(dòng)消息,我們直接返回true就好,否則后面的消息都接受不到

onNestedPreScroll 這個(gè)方法用于消耗內(nèi)層view的一部分滾動(dòng).我們需要將消耗掉的滾動(dòng)存到counsumed中讓consumed知道.例如我們這里在頂部的FrameLayout需要移動(dòng)的情況下會(huì)消耗掉所有的dy,這樣內(nèi)層的view(即RecyclerView)就不會(huì)滾動(dòng)了.

這里的mHeaderHeight保存的是頂部的FrameLayout的高度:

@Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mHeaderHeight = mHeader.getMeasuredHeight();
  }

到這里基本上就實(shí)現(xiàn)了動(dòng)圖的效果,是不是很簡(jiǎn)單?

完整代碼可以參考 https://github.com/bluesky466/NestedScrollDemo/tree/sdk22

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

相關(guān)文章

最新評(píng)論