基要稳

A super-powered FrameLayout—协调布局

2021-12-02  本文已影响0人  Guxxxd

上篇文章介绍了CoordinatorLayout的基本使用 — A super-powered FrameLayout—协调布局CoordinatorLayout(一):深度基本了解

本篇文章说一说Behavior

一、Behavior官方解释

  /**
     * Interaction behavior plugin for child views of {@link CoordinatorLayout}.
     *
     * <p>A Behavior implements one or more interactions that a user can take on a child view.
     * These interactions may include drags, swipes, flings, or any other gestures.</p>
     *
     * @param <V> The View type that this Behavior operates on
     */

CoordinatorLayout直接子view之间相互作用行为的插件.

行为实现了一个或多个用户可以在子view上进行的交互.
这些交互可能包括拖动、滑动、甩动或任何其他手势.

@param <V> 此行为操作的view类型.

二、自定义Behavior

2.1 初识 CoordinatorLayout.Behavior

方法是真的多,就这还删除了被标记@Deprecated的方法,后面会挑捡些重要的方法着重说明

public static abstract class Behavior<V extends View> {

    public Behavior() {}

    public Behavior(Context context, AttributeSet attrs) {}

    public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams params) {}

    public void onDetachedFromLayoutParams() {}

    public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent ev) { return false; }

    public boolean onTouchEvent(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent ev) { return false; }

    @ColorInt
    public int getScrimColor(@NonNull CoordinatorLayout parent, @NonNull V child) { return Color.BLACK; }

    @FloatRange(from = 0, to = 1)
    public float getScrimOpacity(@NonNull CoordinatorLayout parent, @NonNull V child) { return 0.f; }

    public boolean blocksInteractionBelow(@NonNull CoordinatorLayout parent, @NonNull V child) { return getScrimOpacity(parent, child) > 0.f; }

    public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull View dependency) { return false; }

    public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull View dependency) { return false; }

    public void onDependentViewRemoved(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull View dependency) { }

    public boolean onMeasureChild(@NonNull CoordinatorLayout parent, @NonNull V child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { return false; }

    public boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull V child, int layoutDirection) { return false; }

    public static void setTag(@NonNull View child, @Nullable Object tag) { }

    public static Object getTag(@NonNull View child) { }
    
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, @ScrollAxis int axes, @NestedScrollType int type) { }

    public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target,@ScrollAxis int axes, @NestedScrollType int type) { }

    public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, @NestedScrollType int type) { }

    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @NestedScrollType int type, @NonNull int[] consumed) { }
    
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, @NestedScrollType int type) { }

    public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, float velocityX, float velocityY, boolean consumed) { return false; }

    public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, float velocityX, float velocityY) { return false; }
    
    public WindowInsetsCompat onApplyWindowInsets(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull WindowInsetsCompat insets) { return insets; }

    public boolean onRequestChildRectangleOnScreen(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull Rect rectangle, boolean immediate) { return false; }

    public void onRestoreInstanceState(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull Parcelable state) {// no-op}

    public Parcelable onSaveInstanceState(@NonNull CoordinatorLayout parent, @NonNull V child) { return BaseSavedState.EMPTY_STATE; }

    public boolean getInsetDodgeRect(@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull Rect rect) { return false; }
}

2.2 CoordinatorLayout.Behavior<V extends View>的泛型、方法说明

2.2.1 泛型说明

官方释义:此Behavior操作的view类型.
这个Behavior是用在哪种类型的View上,TextViewImageViewButton等等都可以,如果确定了某一种类型,就需要用在对应的那一种类型上;或者直接使用View作为泛型类型,通吃。

2.2.2 方法说明

2.3 自定义CoordinatorLayout.Behavior<V extends View>

2.3.1 明确需求,自定义Behavior一般情况下分为

  1. 此view随着依赖view的状态(位置等)变化而变化


class CustomBehavior : CoordinatorLayout.Behavior<View> {

    companion object {
        private const val TAG = "mr_gu"
    }

    // 列表顶部和title底部重合时,列表的滑动距离。
    private var deltaY = 0f

    constructor()
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    /**
     * 实现Behavior必须要要复写的方法
     */
    override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        Log.i(TAG, "layoutDependsOn: ")
        return dependency is NestedScrollView
    }

    /**
     * 当依赖的view状态发生变化时,设置此behavior的view应当作出的变化
     *
     * 这里实现的是,当NestedScrollView的位置变化时,设置此behavior的view的随着变化
     */
    override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        if (deltaY == 0f) {
            deltaY = dependency.y - child.height
        }
        var dy = dependency.y - child.height
        dy = if (dy < 0) 0f else dy
        val y = -(dy / deltaY) * child.height
        child.translationY = y

        Log.i(TAG, "onDependentViewChanged: ")

        return true
    }
} 
  1. 此view随着依赖view的滑动状态变化而变化


// 滑动状态透明度为0.5f,停止滑动透明度1f
class CustomBehavior : CoordinatorLayout.Behavior<View> {

    companion object {
        private const val TAG = "mr_gu"
    }

    // 列表顶部和title底部重合时,列表的滑动距离。
    private var deltaY = 0f

    constructor()
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    /**
     * 实现Behavior必须要要复写的方法
     */
    override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        Log.i(TAG, "layoutDependsOn: ")
        return dependency is NestedScrollView
    }
    
    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: View,
                                     directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
        Log.i(TAG, "onStartNestedScroll: ")
        // 只分发垂直滑动
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL
    }

    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: View, target: View, type: Int) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type)
        child.visibility = View.VISIBLE
        child.alpha = 1f
        Log.i(TAG, "onStopNestedScroll: ")
    }

    override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: View, target: View, dxConsumed: Int,
        dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int, consumed: IntArray) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
            dxUnconsumed, dyUnconsumed, type, consumed)
        Log.i(TAG, "onNestedScroll: ")
         // 也可以拿到当次滑动的距离
        child.alpha = 0.5f
    }
}
  1. 1 + 2


三、总结与思考

使用Behavior可以较为方便的实现页面中view间相互作用的效果,文章中的例子都是最简单的效果,面对设计小姐姐天马行空的设计和想法,Behavior可能会帮助你很好的应对,不至于扎耳挠腮,骂骂咧咧,还容易掉头发

Behavior是底层逻辑是什么样的,为什么在xml中简单的配置个Behavior属性就可以实现,答案都在源码中,read the fucking resource code ,can help you grow quickly

【本文参考】
SheHuan —— Android CoordinatorLayout之自定义Behavior


如果文章对你有帮助,点个赞再走呗

如果文章中存在错误,还望评论区指出

一起成长,共同进步

上一篇下一篇

猜你喜欢

热点阅读