日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Coordinatorlayout嵌套滑动,自定义Behavior,听我来讲讲?

發布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Coordinatorlayout嵌套滑动,自定义Behavior,听我来讲讲? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 分析
    • 1、父容器子容器
    • 2、如何形成關聯,誰是發起者
    • 3、NestedScrollingParent和NestedScrollingChild對應
    • 4、響應者
  • 示例


前言

嵌套滑動,顧名思義,嵌套嵌套就一定有父容器和子容器。如何能讓子容器滑動能帶動父容器(或父容器包含的其他子容器)滑動?什么樣的子容器有這種能力?這種關聯如何形成,以及被關聯的容器如何響應,這種響應的邏輯在哪里定義?
相信你在對本文的閱讀之后會有一定的了解


提示:以下是本篇文章正文內容

分析

1、父容器子容器

了解安卓開發的同學對這個概念再熟悉不過了,父容器是容器布局,子容器(控件)則是被這個父容器包含的容器布局(控件)。如:

<FrameLayout><RelativeLayout>...</RelativeLayout><View/> </FrameLayout>

這里的FrameLayout就是父容器,這里的RelativeLayout和View就是子容器(控件)。

2、如何形成關聯,誰是發起者

父容器實現NestedScrollingParent接口,
子容器實現NestedScrollingChild接口。

查看代碼示例

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout><android.support.design.widget.AppBarLayout/><FrameLayoutapp:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"><android.support.v7.widget.RecyclerView/><!--懸浮條--><RelativeLayout>...</RelativeLayout></FrameLayoutapp:layout_behavior=".ScaleBehavior"><android.support.design.widget.FloatingActionButton/> </android.support.design.widget.CoordinatorLayout>

示例中的CoordinatorLayout默認實現了NestedScrollingParent接口,而RecyclerView控件默認實現了NestedScrollingChild接口。

所以在RecyclerView滑動的時候,CoordinatorLayout一直能收到相應的回調。比如說這時候這個控件不是RecyclerView而是ListView的話,那這個回調自然是沒有的,理由就是ListView并沒有默認實現NestedScrollingChild接口。

實現了NestedScrollingChild接口的控件,其實也就是整個事件的發起者,而父容器便是接受的一方。

3、NestedScrollingParent和NestedScrollingChild對應

這兩個接口的回調方法api,如下:

SCROLL_STATE_IDLE 0, 最后是RecyclerView滾動停止狀態。 SCROLL_STATE_DRAGGING 1, 先是手指拖拽的狀態 SCROLL_STATE_SETTLING 2,再是手指松開但是RecyclerView還在滑動/** *父容器實現的接口 */ public interface NestedScrollingParent {/*** 開始滑動回調* @param child 該父View 的子View* @param target 支持嵌套滑動的 VIew* @param nestedScrollAxes 滑動方向* @return 是否支持 嵌套滑動*/boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int nestedScrollAxes);void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int nestedScrollAxes);void onStopNestedScroll(@NonNull View target);/*** 這里 傳來了 x y 方向上的滑動距離* 并且 先與 子VIew 處理滑動, 并且 consumed 中可以設置相應的 除了的距離* 然后 子View 需要更具這感覺, 來處理自己滑動** @param target* @param dx* @param dy* @param consumed*/void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed);/*** 這里 主要處理 dyUnconsumed dxUnconsumed 這兩個值對應的數據* @param target* @param dxConsumed* @param dyConsumed* @param dxUnconsumed* @param dyUnconsumed*/void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed);boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY);boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed);int getNestedScrollAxes(); }/** *子容器(控件)實現的接口 */ public interface NestedScrollingChild {//設置允許嵌套滑動 true表示允許void setNestedScrollingEnabled(boolean enable);boolean isNestedScrollingEnabled();//開始嵌套滑動 這里需要返回true 否在后續事件不會再觸發boolean startNestedScroll(int axes);//坐標軸//結束嵌套滑動void stopNestedScroll();//判斷NestedParent的onStartNestedScroll是否返回true 只有為true后續的事件才能繼續一系列的嵌套滑動boolean hasNestedScrollingParent();//子view消費了拖動事件之前通知父view,dx dy是將要消費的距離,如果父view要消費可通過//設置consumed[0]=x .consumed[1]=y來分別消費x,y。然后子view繼續處理剩下的位移(即dx-x,dy-y)boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow);//子View消費滑動事件后通知父Viewboolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow);//子view消費了滑動事件之前通知父viewboolean dispatchNestedPreFling(float var1, float var2);//子view消費了滑動事件之后通知父viewboolean dispatchNestedFling(float var1, float var2, boolean var3); }

父接口的回調和子接口的回調,兩者的方法有明顯的對應關系。

這樣實現了子接口就可以在需要的時候調用接口的方法,如stopNestedScroll,這樣對應在父接口onStopNestedScroll也就會被回調。

4、響應者

上文說了父容器是接受的一方,但它并不是真正意義上的響應者,響應者是誰取決于Behavior的定義。

本例中的父容器是CoordinatorLayout,我們就可以自定義一個Behavior繼承CoordinatorLayout.Behavior,然后在對應的父容器回調方法中加入自己想要的邏輯。

值得一提的是,你即可以指定設置了Behavior的控件本身響應,也可以指定該父容器下的其他子容器(控件)響應,無論這個Behavior設置給哪個子容器(控件)。

示例如下:

public class ScaleBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {@Overridepublic boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {//只有返回true 后續的動作才會觸發return axes == ViewCompat.SCROLL_AXIS_VERTICAL;//垂直滾動}@Overridepublic void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);...} }

當然Android本身也有很多定義好的Behavior可以直接使用,這里就不贅述了。

最后將這個Behavior設置到布局中,就可以正常使用了。

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout><android.support.design.widget.AppBarLayout/><FrameLayoutapp:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"><android.support.v7.widget.RecyclerView/><!--懸浮條--><RelativeLayout>...</RelativeLayout></FrameLayoutapp:layout_behavior=".ScaleBehavior"><android.support.design.widget.FloatingActionButton/> </android.support.design.widget.CoordinatorLayout>

示例

本例主要

  • 使用RecyclerView做示范。(將項目啟動頁改為MainActivity查看)
  • 自定義了一個實現了NestedScrollingChild接口的ListView做示范。
  • 自定義Behavior示范。

效果如下

總布局代碼如下

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><android.support.design.widget.AppBarLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><android.support.v7.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="?actionBarSize"app:layout_scrollFlags="scroll|enterAlways"app:title="ToolBar" /></android.support.design.widget.AppBarLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"><pers.owen.recyclerview.NestedListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"tools:listitem="@layout/item_feed" /><!--懸浮條--><RelativeLayoutandroid:id="@+id/suspension_bar"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@android:color/white"><pers.owen.recyclerview.CircleImageViewandroid:id="@+id/iv_avatar"android:layout_width="44dp"android:layout_height="44dp"android:padding="8dp"android:src="@drawable/avatar1" /><TextViewandroid:id="@+id/tv_nickname"android:layout_width="wrap_content"android:layout_height="44dp"android:layout_marginLeft="8dp"android:layout_toRightOf="@id/iv_avatar"android:gravity="center_vertical"android:text="粥可溫"android:textSize="12sp" /><Viewandroid:id="@+id/top_divider"android:layout_width="match_parent"android:layout_height="0.2dp"android:layout_below="@id/tv_nickname"android:background="#33000000" /></RelativeLayout></FrameLayout><android.support.design.widget.FloatingActionButtonandroid:layout_width="48dp"android:layout_height="48dp"android:layout_gravity="bottom|right"android:layout_margin="16dp"app:layout_behavior=".ScaleBehavior" /> </android.support.design.widget.CoordinatorLayout>

NestedListView代碼如下

public class NestedListView extends ListView implements NestedScrollingChild {//1初始化獲取ChildHelperprivate NestedScrollingChildHelper mChildHelper;private int mLastY;private final int[] mScrollOffset = new int[2];//滑動偏移private final int[] mScrollConsumed = new int[2];//滑動消費private int mNestedOffsetY;//嵌套偏移public NestedListView(Context context) {super(context);init();}public NestedListView(Context context, AttributeSet attrs) {super(context, attrs);init();}public NestedListView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mChildHelper = new NestedScrollingChildHelper(this);setNestedScrollingEnabled(true);}@Overridepublic void setNestedScrollingEnabled(boolean enabled) {mChildHelper.setNestedScrollingEnabled(enabled);}@Overridepublic boolean isNestedScrollingEnabled() {return mChildHelper.isNestedScrollingEnabled();}@Overridepublic boolean startNestedScroll(int axes) {return mChildHelper.startNestedScroll(axes);}@Overridepublic void stopNestedScroll() {mChildHelper.stopNestedScroll();}@Overridepublic boolean hasNestedScrollingParent() {return mChildHelper.hasNestedScrollingParent();}@Overridepublic boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);}@Overridepublic boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);}@Overridepublic boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);}@Overridepublic boolean dispatchNestedPreFling(float velocityX, float velocityY) {return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {int action = ev.getAction();int y = (int) ev.getY();ev.offsetLocation(0, mNestedOffsetY);switch (action) {case MotionEvent.ACTION_DOWN:mLastY = y;mNestedOffsetY = 0;this.startNestedScroll((ViewCompat.SCROLL_AXIS_VERTICAL));//開始嵌套滑動break;case MotionEvent.ACTION_MOVE:int dy = mLastY - y;//Y的拖動距離int oldY = getScrollY();//注意一般一直為0//在自己消費前先分發給父容器if (dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)) {dy -= mScrollConsumed[1];//剩余ev.offsetLocation(0, -mScrollOffset[1]);mNestedOffsetY += mScrollOffset[1];}mLastY = y - mScrollOffset[1];int newScrollY = oldY + dy;dy -= newScrollY - oldY;//全部消費完//自己消費if (dispatchNestedScroll(0, newScrollY - dy, 0, dy, mScrollOffset)) {ev.offsetLocation(0, mScrollOffset[1]);mNestedOffsetY += mScrollOffset[1];mLastY -= mScrollOffset[1];}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:stopNestedScroll();break;}return super.onTouchEvent(ev);} }

ScaleBehavior代碼如下

public class ScaleBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {private Interpolator interpolator;private boolean isRunning;public ScaleBehavior(Context context, AttributeSet attrs) {super(context, attrs);interpolator = new AccelerateDecelerateInterpolator();}@Overridepublic boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {//只有返回true 后續的動作才會觸發return axes == ViewCompat.SCROLL_AXIS_VERTICAL;//垂直滾動}@Overridepublic void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);Log.e("test", dyConsumed + " " + dyUnconsumed);if (dyConsumed > 0 && !isRunning && child.getVisibility() == View.VISIBLE) {//上滑 縮小隱藏 動畫scaleHide(child);} else if (dyConsumed < 0 && !isRunning && child.getVisibility() == View.INVISIBLE) {//下滑 放大顯示scaleShow(child);}}private void scaleShow(final V child) {child.setVisibility(View.VISIBLE);ViewCompat.animate(child).alpha(1).scaleX(1).scaleY(1).setInterpolator(interpolator).setListener(new ViewPropertyAnimatorListener() {@Overridepublic void onAnimationStart(View view) {isRunning = true;}@Overridepublic void onAnimationEnd(View view) {isRunning = false;}@Overridepublic void onAnimationCancel(View view) {isRunning = false;}}).setDuration(500).start();}private void scaleHide(final V child) {ViewCompat.animate(child).alpha(0).scaleX(0).scaleY(0).setInterpolator(interpolator).setListener(new ViewPropertyAnimatorListener() {@Overridepublic void onAnimationStart(View view) {isRunning = true;}@Overridepublic void onAnimationEnd(View view) {isRunning = false;child.setVisibility(View.INVISIBLE);}@Overridepublic void onAnimationCancel(View view) {isRunning = false;}}).setDuration(500).start();} }

推薦閱讀

Android 11新特性,Scoped Storage又有了新花樣

About

本文Demo

UI系列文章一覽

總結

以上是生活随笔為你收集整理的Coordinatorlayout嵌套滑动,自定义Behavior,听我来讲讲?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。