FloatingActionButton设置Behavior只能执行一次原因以及解决办法

这两天重构项目,遇到需要添加一个Fab的时候,就随便上网上copy了一段代码,测试的时候发现,只能执行一次,之后就不会走Behavior的onNestedScroll方法了。
在网上找了半天解决办法,也没有找到。最后只能看看源码到底是因为什么吧,直接上源码


@Override
public boolean onStartNestedScroll(View child, View target, int axes, int type) {
    boolean handled = false;

    final int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        final View view = getChildAt(i);
        if (view.getVisibility() == View.GONE) {
            // If it's GONE, don't dispatch
            continue;
        }
        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
        final Behavior viewBehavior = lp.getBehavior();
        if (viewBehavior != null) {
            final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child,
                    target, axes, type);
            handled |= accepted;
            lp.setNestedScrollAccepted(type, accepted);
        } else {
            lp.setNestedScrollAccepted(type, false);
        }
    }
    return handled;
}

自定义的Behavior中的onStartNestedScroll方法最后会走到CoordinatorLayout方法的onStartNestedScroll方法中 在里面判断了一下childView的visibility的属性是不是GONE 是的话就会跳过

同样的onNestedScroll中也会判断childView的属性,是GONE的时候就回跳过。所以在设置需要执行Behavior的View的属性就不要设置成GONE就可以了。

@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
        int dxUnconsumed, int dyUnconsumed, int type) {
    final int childCount = getChildCount();
    boolean accepted = false;

    for (int i = 0; i < childCount; i++) {
        final View view = getChildAt(i);
        if (view.getVisibility() == GONE) {
            // If the child is GONE, skip...
            continue;
        }

        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
        if (!lp.isNestedScrollAccepted(type)) {
            continue;
        }

        final Behavior viewBehavior = lp.getBehavior();
        if (viewBehavior != null) {
            viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,
                    dxUnconsumed, dyUnconsumed, type);
            accepted = true;
        }
    }

    if (accepted) {
        onChildViewsChanged(EVENT_NESTED_SCROLL);
    }
}


最后附上自己写的BaseBehavior以及一个可用的Behavior


open class BaseBehavior constructor(context: Context,attrs:AttributeSet): CoordinatorLayout.Behavior(){

    private val mFastInterpolator = FastOutSlowInInterpolator()


    // 显示view
    fun scaleShow(view: View,l :ListenerAnimatorEndBuild?) {
        view.visibility = View.VISIBLE
        ViewCompat.animate(view)
                .scaleX(1.0f)
                .scaleY(1.0f)
                .alpha(1.0f)
                .setDuration(500)
                .setListener(l?.build())
                .setInterpolator(mFastInterpolator)
                .start()
    }


    // 隐藏view
    fun scaleHide(view: View,l:ListenerAnimatorEndBuild?) {
        ViewCompat.animate(view)
                .scaleX(0.0f)
                .scaleY(0.0f)
                .alpha(0.0f)
                .setDuration(500)
                .setInterpolator(mFastInterpolator)
                .setListener(l?.build())
                .start()
    }


    class ListenerAnimatorEndBuild {
        // 记录View移出动画是否执行完。
        private var isOutExecute = false

        private val outAnimatorListener: ViewPropertyAnimatorListener

        // View移出动画是否执行完。
        val isFinish: Boolean
            get() = !isOutExecute

        init {
            outAnimatorListener = object : ViewPropertyAnimatorListener {
                override fun onAnimationStart(view: View) {
                    isOutExecute = true
                }

                override fun onAnimationEnd(view: View) {
                    view.visibility = View.INVISIBLE
                    isOutExecute = false
                }

                override fun onAnimationCancel(view: View) {
                    isOutExecute = false
                }
            }
        }

        // 返回ViewPropertyAnimatorListener。
        fun build(): ViewPropertyAnimatorListener {
            return outAnimatorListener
        }
    }

}


class FabBehavior constructor(context: Context, attributeSet: AttributeSet) : BaseBehavior(context, attributeSet) {

    private var  listenerAnimatorEndBuild = ListenerAnimatorEndBuild()

    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,
                                     child: FloatingActionButton,
                                     directTargetChild: View,
                                     target: View, axes: Int, type: Int): Boolean {
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL
    }


    override fun onNestedScroll(coordinatorLayout: CoordinatorLayout,
                                child: FloatingActionButton,
                                target: View,
                                dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int,
                                type: Int) {
        if (dyConsumed > 0 && dyUnconsumed == 0) {
            KLog.d("behavior", "上滑中。。。")
        }
        if (dyConsumed == 0 && dyUnconsumed > 0) {
            KLog.d("behavior", "到边界了还在上滑。。。")
        }
        if (dyConsumed < 0 && dyUnconsumed == 0) {
            KLog.d("behavior", "下滑中。。。")
        }
        if (dyConsumed == 0 && dyUnconsumed < 0) {
            KLog.d("behavior", "到边界了,还在下滑。。。")
        }

        //页面向上滑动像素数大于0 || 拉到底还在向上拉 && 退出动画是否正在执行 && FAB按钮当前显示中
        if ((dyConsumed > 0 || dyUnconsumed > 0) && listenerAnimatorEndBuild.isFinish&& child.visibility == View.VISIBLE) {
            //隐藏Fab
            scaleHide(child,listenerAnimatorEndBuild)
        } else if ((dyConsumed < 0 || dyUnconsumed < 0) && child.visibility != View.VISIBLE) {
            //显示Fab按钮
            scaleShow(child,null)
        }
    }
    
}

copy过去就能用了 部分动画代码是上网上找的,毕竟我懒的写。。。
至于是kotlin写的也没关系,之间copy的话 as会自动转为java的。

你可能感兴趣的:(FloatingActionButton设置Behavior只能执行一次原因以及解决办法)