×
广告

关于BottomSheetBehavior、BottomSheetDialog和SwipeDismissBehavior

96
苍蝇的梦
2017.01.16 14:29* 字数 417

2017-01-13 遇到的一点小问题

之前用到Behavior只是按网上看到的方式来做个简单点的滑动隐藏显示顶部View,
CoordinatorLayout与AppBarLayout配合使用的滑动效果 这个提过了。
前几天看到利用自定义Behavior,打造动画效果,打算了解看看,先从最简单的开始。
http://www.jianshu.com/p/82d18b0d18f4
BottomSheetBehavior的用法很简单,将View放在android.support.design.widget.CoordinatorLayout布局里,再加上app:layout_behavior="@string/bottom_sheet_behavior"这个属性就可以。这样是默认显示的,如果要默认隐藏就再加上app:behavior_peekHeight="0dp"。没找到能在底部上滑让底部View出现的方法,只好将peekHeight设置为5dp,这样,在折叠时,也能上滑让底部View出现。
BottomSheetBehavior有好几个状态,默认收起来是STATE_COLLAPSED折叠状态,如果你希望是STATE_HIDDEN隐藏状态,就要加上bottomSheetBehavior.setHideable(true);看源码可知道,mHideable 默认是false,如果不改成true,在bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);时就会抛出异常

    /**
     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
     * animation.
     *
     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
     *              {@link #STATE_HIDDEN}.
     */
    public final void setState(final @State int state) {
        if (state == mState) {
            return;
        }
        if (mViewRef == null) {
            // The view is not laid out yet; modify mState and let onLayoutChild handle it later
            if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
                    (mHideable && state == STATE_HIDDEN)) {
                mState = state;
            }
            return;
        }
        final V child = mViewRef.get();
        if (child == null) {
            return;
        }
        // Start the animation; wait until a pending layout if there is one.
        ViewParent parent = child.getParent();
        if (parent != null && parent.isLayoutRequested() && ViewCompat.isAttachedToWindow(child)) {
            child.post(new Runnable() {
                @Override
                public void run() {
                    startSettlingAnimation(child, state);
                }
            });
        } else {
            startSettlingAnimation(child, state);
        }
    }

    void startSettlingAnimation(View child, int state) {
        int top;
        if (state == STATE_COLLAPSED) {
            top = mMaxOffset;
        } else if (state == STATE_EXPANDED) {
            top = mMinOffset;
        } else if (mHideable && state == STATE_HIDDEN) {
            top = mParentHeight;
        } else {
            throw new IllegalArgumentException("Illegal state argument: " + state);
        }
        setStateInternal(STATE_SETTLING);
        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
        }
    }

所为,如果我们没必要监听他的状态变化和滑动距离,只是点击别的按钮让他展开和折叠,使用方法就特别简单了。

final BottomSheetBehavior<View> bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom));
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if(bottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED){
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                }else {
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                }
    }
});

BottomSheetDialog用法和普通的自定义Dialog没差。

BottomSheetDialog dialog = new BottomSheetDialog(context);
View view = LayoutInflater.from(context).inflate(R.layout.dialog_behavior,null);
dialog.setContentView(view);
dialog.show();

SwipeDismissBehavior滑动删除,效果和Snackbar滑动删除的一样。
可以参考http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1103/3650.html 的用法,也可以按 http://www.cnblogs.com/yuanchongjie/p/4997134.html 写的,参考android.support.design.widget.Snackbar的源码来操作。

Snackbar的showView()

确保使用SwipeDismissBehavior的View在android.support.design.widget.CoordinatorLayout布局里面。 http://blog.csdn.net/wuyuxing24/article/details/51160182 这边也有写了几个主要方法的中文注释,英语不好可以参考。这样就没问题了。滑动后,View并不是真的消失,他还是VISIBLE,只是Alpha变成0,不过自己改成1也不会再显示的,这个还不知道怎么让他再显示。
使用SwipeDismissBehavior滑动,不限于单个View,而是整个在LayoutParams里的View都可以。如果要只限制某个View能滑动,需要参考Snackbar的源码,自己定义一个 MySwipeDismissBehavior继承extends android.support.design.widget.SwipeDismissBehavior,然后重写boolean canSwipeDismissView(@NonNull View view)方法,根据条件来return truereturn false,默认是所有都return true。可以通过boolean canSwipeDismissView(@NonNull View view)来查询某个View是否能滑动删除。
继续看自定义Behavior。

Android
Web note ad 1