Need help with WangyiyunBottomSheetDialog?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

af913337456
215 Stars 30 Forks 6 Commits 2 Opened issues

Description

网易云音乐效果的-BottomSheetDialog,Slide, rebound

Services available

!
?

Need anything else?

Contributors list

No Data

作者:林冠宏 / 指尖下的幽灵

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities


首先是-- Android SDK 自带的
BottomSheetDialog

下面的 gif 图是一个Android SDK 自带的

BottomSheetDialog
内部加了
RecyclerView
列表控件的效果

可以看出: * 下滑动作会收起,隐藏掉

dialog
* 上滑会完全展开 * 展开后,才能滑动
RecyclerView
内部

其次 * 如果你内部使用的是

ListView
列表控件,你会发现会有其他奇怪的情况。

然后是--网易云音乐 的
BottomSheetDialog

下面的 gif 图是一个Android 版

网易云音乐
BottomSheetDialog
效果

可以看出: * 下滑动作会有

范围
回弹,也就是下滑到一定距离才会收起,隐藏掉
dialog
* 上滑不给展开 * 能够在半展开的情况下,内嵌滑动列表控件,例如
listView
* 和列表控件滑动不冲突,在
列表控件
滑尽的时候,可以下滑隐藏
dialog

最后是--我开源 的仿网易云音乐
BottomSheetDialog

可以看出,效果和

网易云的一样

核心代码简述

SDK 的 BottomSheetDialog 内部布局的结构如下: ```java --FrameLayout --|--CoordinatorLayout --|--|--FrameLayout --|--|--|--Our ContentView // 最后是我们设置的 ContentView

CoordinatorLayout 在 `Action_Move` 事件时,必要的时候对其子 View 进行事件拦截,所以有第一个 gif 看到的效果,具体不详说。

第一个步骤 --- 防止 CoordinatorLayoutOur ContentView 拦截事件

这里使用 ListView 做例子,设置onTouch,在内部做适当时候的适当阻止CoordinatorLayout 拦截事件。

```java // ListView setOnTouchListener( new OnTouchListener() { @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { if (bottomCoordinator == null) return false; // 拿出当前列表第一个可见 item 的 pos int firstVisiblePos = getFirstVisiblePosition(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downY = event.getRawY(); bottomCoordinator.requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: moveY = event.getRawY(); if ((moveY - downY) > 10) { // 下滑情况 if (firstVisiblePos == 0 && isOverScroll) { // 列表控件,例如 listView 已经滑到头了,允许被拦截 bottomCoordinator.requestDisallowInterceptTouchEvent(false); break; } } // 上滑时,总是不允许被拦截,listView 消耗当前事件 bottomCoordinator.requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: break; } return false; } } );

第二个步骤,让
ListView
能在半展开的情况下,显示完整的数据条数

重写

onMeasure
,使用自定义的测量模式。
// ListView
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if(bottomCoordinator == null){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }
    // 以黄金分割的尺寸来显示 listView 的高度
    int size = (int)((float)(getResources().getDisplayMetrics().heightPixels*0.618));
    int newHeightSpec = MeasureSpec.makeMeasureSpec(
            size,
            // mode,非法的情况,super 直接使用 size 做高,看源码后,你会发现也可以使用 exact 模式
            Integer.MIN_VALUE
    );
    super.onMeasure(widthMeasureSpec, newHeightSpec);
}

第三个步骤,实现
BottomSheetDialog
范围回弹

/**
 * 添加 top 距离顶部多少的时候触发收缩效果
 * @param targetLimitH int 高度限制
 */
@SuppressWarnings("all")
public void addSpringBackDisLimit(final int targetLimitH){
    if(coordinator == null)
        return;
    // totalHeight 屏幕的总像素高度
    final int totalHeight = getContext().getResources().getDisplayMetrics().heightPixels;
    // currentH 当前我们的 列表控件 展开的高度
    final int currentH = (int) ((float)totalHeight*0.618); // 0.618 是黄金分割点,随便自定义,对应 contentView
    final int leftH    = totalHeight - currentH;
    coordinator.setOnTouchListener(
            new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()){
                        case MotionEvent.ACTION_MOVE:
                            // 计算相对于屏幕的 坐标
                            bottomSheet.getGlobalVisibleRect(r);
                            break;
                        case MotionEvent.ACTION_UP:
                            // 抬手的时候判断
                            int limitH;
                            if(targetLimitH < 0)
                                limitH = (leftH + currentH/3);
                            else
                                limitH = targetLimitH;
                            if(r.top <= limitH)
                                if (mBehavior != null)
                                    // 范围内,让它继续是 半展开的状态
                                    mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                            break;
                    }
                    return false;
                }
            }
    );
}

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.