自定义Behavior(二)

本文介绍如何通过自定义Behavior实现视图组件跟随滑动状态显示或隐藏的效果。重点讲解了onStartNestedScroll和onNestedScroll方法的使用,并提供了一个具体的实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上次讲了自定义Behavior的child监听dependency的状态变化,这次就接着说child监听实现了NestedScrollingChild的接口的dependency的滑动状态。
需要重写两个方法

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }

先来看onStartNestedScroll,这个方法表明我们在这次滑动中关心的方向,如果是X轴,则return nestedScrollAxes == ViewCompat.SCROLL_AXIS_HORIZONTAL;若是关心Y轴方向的滑动,return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL即可。

onNestedScroll这个方法才是我们关注的重点,coordinatorLayout这个参数就不说了,child是指设置了这个Behavior的coordinatorLayout的子View,target则是前面提到的实现了NestedScrollingChild的接口的dependency。dxConsumed、dyConsumed是指x、y轴方向上target消费的像素值,简单来说,就是滚动的距离,至于后面两个参数,百度了,也看了源码的注释,还是不太明白,翻译过来字面意思就是:不被目标自身的滚动操作所消耗的垂直、水平像素,而是用户要求的(本来以为是调用scrollto之类方法产生的,试过了发现不是)。

说完这么多屁话,看个例子
先上效果图
这里写图片描述
仔细看还是和之前的有点区别,在上滑和下滑时,隐藏显示FloatingActionButton和BottomBar。

XML

<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/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:elevation="0dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="topBar"
            app:layout_scrollFlags="scroll|enterAlways" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none"
        app:behavior_overlapTop="30dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <include layout="@layout/layout_main" />

    </android.support.v4.widget.NestedScrollView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_gravity="bottom"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="bottomBar"
        app:layout_behavior=".BottomScrollBehavior" />

    <android.support.design.widget.FloatingActionButton
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="bottom|right"
        android:layout_marginBottom="70dp"
        android:layout_marginRight="20dp"
        android:src="@mipmap/ic_launcher_round"
        app:elevation="5dp"
        app:layout_behavior=".ScrollingBehavior" />
</android.support.design.widget.CoordinatorLayout>

也和上一篇的相似,唯一的区别就是BottomBar和FloatingActionButton的Behavior换了
再看自定义的Behavior

ScrollingBehavior

public class ScrollingBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
    //是否正在执行动画的标示符
    private boolean isAnimator;

    public ScrollingBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimator && child.getVisibility() == View.VISIBLE) {
            hideAnimator(child);

        } else if ((dyConsumed < 0 || dyUnconsumed < 0) && !isAnimator && child.getVisibility() != View.VISIBLE) {
            showAnimator(child);
        }
    }

    private void showAnimator(View view) {
        view.setVisibility(View.VISIBLE);
        ViewCompat.animate(view)
                .scaleX(1.0f)
                .scaleY(1.0f)
                .alpha(1.0f)
                .setDuration(800)
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {
                        isAnimator = true;
                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        isAnimator = false;
                    }

                    @Override
                    public void onAnimationCancel(View view) {
                        isAnimator = false;
                    }
                })
                .start();
    }

    private void hideAnimator(View view) {
        ViewCompat.animate(view)
                .scaleX(0)
                .scaleY(0)
                .alpha(0)
                .setDuration(800)
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {
                        isAnimator = true;
                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        isAnimator = false;
                        view.setVisibility(View.INVISIBLE);
                    }

                    @Override
                    public void onAnimationCancel(View view) {
                        isAnimator = false;
                    }
                })
                .start();
    }
}

BottomScrollBehavior

public class BottomScrollBehavior extends CoordinatorLayout.Behavior<View> {
    private boolean isAnimator;

    public BottomScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimator && child.getTranslationY() == 0) {
            hideAnimator(child);

        } else if ((dyConsumed < 0 || dyUnconsumed < 0) && !isAnimator && child.getTranslationY() == child.getHeight()) {
            showAnimator(child);
        }
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }

    private void showAnimator(View view) {
        ViewCompat.animate(view)
                .translationY(0)
                .setDuration(800)
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {
                        isAnimator = true;
                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        isAnimator = false;
                    }

                    @Override
                    public void onAnimationCancel(View view) {
                        isAnimator = false;
                    }
                })
                .start();
    }

    private void hideAnimator(View view) {
        ViewCompat.animate(view)
                .translationY(view.getHeight())
                .setDuration(800)
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {
                        isAnimator = true;
                    }

                    @Override
                    public void onAnimationEnd(View view) {
                        isAnimator = false;
                    }

                    @Override
                    public void onAnimationCancel(View view) {
                        isAnimator = false;
                    }
                })
                .start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值