国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android嵌套滾動NestedScroll的實現了解一下

2019-12-12 00:48:53
字體:
來源:轉載
供稿:網友

其實嵌套滾動已經算一個比較常見的特效了,下面這個動圖就是嵌套滾動的一個例子:

看到這個動效,大家可能都知道可以用CoordinatorLayout去實現.其實CoordinatorLayout是基于NestedScroll機制去實現的,而我們直接通過NestedScroll機制也能很方便的實現這個動效.

原理

NestedScroll的其實很簡單.

一般的觸摸消息的分發都是從外向內的,由外層的ViewGroup的dispatchTouchEvent方法調用到內層的View的dispatchTouchEvent方法.

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

上面的描述可能有點繞,可以看下面的圖來幫助理解:

 

具體實現

NestedScroll機制會涉及到四個類:

NestedScrollingChild, NestedScrollingChildHelper 和 NestedScrollingParent , NestedScrollingParentHelper

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

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();}

這里真正重要的其實是NestedScrollingParent的幾個方法,因為其他方法都能直接讓NestedScrollingChildHelper或者NestedScrollingParentHelper去代理:

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

我們只要讓子view和父view分別實現NestedScrollingChild和NestedScrollingParent接口,然后分別調用NestedScrollingChildHelper和NestedScrollingParentHelper的對應方法去代理一些具體功能,然后在NestedScrollingChild的onTouchEvent那里根據需求調用startNestedScroll/dispatchNestedPreScroll/stopNestedScroll就能實現嵌套滾動了:

//NestedScrollingChildprivate 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);}...
//NestedScrollingParentprivate 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機制已經直接集成到了View中了,你只需要直接重寫View的對應方法就好

布局

我們先看布局文件

<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,其實它是一個LinearLayout,內部豎直排列了三個子view:

  1. 一個由FrameLayout包裹的ImageView
  2. 一個TextView
  3. 一個RecyclerView

代碼

為了簡便起見,我們先直接用sdk22的版本用重寫View方法的方式去實現它.

NestedScrollParentView中有兩個方法比較重要,嵌套滾動基本上就是由這兩個方法實現的:

@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 這個方法如果返回true的話代表接受由內層傳來的滾動消息,我們直接返回true就好,否則后面的消息都接受不到

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

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

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

到這里基本上就實現了動圖的效果,是不是很簡單?

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 屏山县| 西乌珠穆沁旗| 调兵山市| 乌恰县| 康马县| 滨海县| 隆化县| 宜兴市| 嘉义市| 汾西县| 吉林省| 新巴尔虎右旗| 克拉玛依市| 禹城市| 桂阳县| 藁城市| 油尖旺区| 牟定县| 玉田县| 河源市| 河间市| 永修县| 汽车| 资兴市| 秦皇岛市| 南充市| 积石山| 顺昌县| 博罗县| 西畴县| 治多县| 阿勒泰市| 正安县| 武穴市| 涡阳县| 特克斯县| 福安市| 洞头县| 南丹县| 宁蒗| 武乡县|