Android 记录一下BottomSheet的Behavior案例

先看图:


1637121451617.gif

最近朋友遇到的需求:
1、底部的布局需要上下拖动,且只能拖动顶部标题栏
2、未展开和展开状态都要能滑动图标列表
3、要能点击后面的黑色区域,因为后面可能放一个图片可以收缩放大等。
遇到的问题:
1、要能点击后面的黑色区域就不能用dialog,如果要用dialog那就要处理能点击到后面activity的逻辑,就要加WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE的配置。
2、BottomSheet的拖动是对应整个布局都可以滑动的,如果只能滑动标题就要把最外层布局设为自定义然后监听按下的y值是否在标题区域内,是就打开滑动,否就关闭滑动。
3、在未展开状态下。列表滑动到最底部未展示最后一条,这和BottomSheet移动的距离有关recycleview被移到屏幕外了,解决办法就是给recycleview一个paddingbottom,然后移动的时候也事实改变这个paddingbottom。

代码简单,就不做细致分析了。记录一下,万一以后用到了呢?
先看activity布局



    
        
    
    
        

        
    

app:layout_behavior="@string/bottom_sheet_behavior"就能让这个布局滑动起来,有人说布局一定要是带滑动属性的布局才行,其实并不需要。然后我们不需要三级滑动,什么叫三级滑动呢?当我们进入页面布局先是折叠状态然后我们可以拉伸撑满全屏,最后我们往下滑可以让他完全退出到屏幕外,这三种状态就被人称之为三级滑动。这里我们不需要完全退出,它最小也要漏出250dp,所以我们设置

app:behavior_hideable="false"
app:behavior_peekHeight="250dp"

布局里面还有一点需要注意,在折叠状态时,我们滑动列表会发现很卡,我们只需要在recycleview里面加上android:nestedScrollingEnabled="false"就行,CoordinatorLayout里面经常遇到的事。
然后看activity代码

public class DragDialogActivity extends AppCompatActivity implements View.OnClickListener {

    private MyRelativeLayout mBottomSheetContent;
    private BottomSheetBehavior mBehavior;
    private RecyclerView mRecyclerView;
    private TestAdapter mAdapter;
    private TabLayout mTitleTab;
    private int mPaddingBottomValue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drag_dialog);
        initView();
    }

    private void initView() {
        setBottomSheetState();
        initRecycleView();
        findViewById(R.id.mIv).setOnClickListener(this);
    }

    private void initRecycleView() {
        mRecyclerView = findViewById(R.id.mRecyclerView);
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
        mAdapter = new TestAdapter();
        mRecyclerView.setAdapter(mAdapter);

        //解決展示不全的问题
        mBottomSheetContent.post(new Runnable() {
            @Override
            public void run() {
                int parentHeight = mBottomSheetContent.getHeight();
                mPaddingBottomValue = parentHeight - mBehavior.getPeekHeight();
                //计算出mRecycleview需要距离底部的偏移量
                mRecyclerView.setPadding(0,0,0,mPaddingBottomValue);
            }
        });

        //标题列表
        mTitleTab = findViewById(R.id.mTitleTab);
        initTestTitles();
    }

    private void initTestTitles() {
        for (int i = 0; i < 20; i++) {
            mTitleTab.addTab(mTitleTab.newTab().setText("标题"+i));
        }
    }

    private void setBottomSheetState() {
        mBottomSheetContent = findViewById(R.id.mBottomSheetContent);
        mBehavior = BottomSheetBehavior.from(mBottomSheetContent);
        mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        mBottomSheetContent.setBehavior(mBehavior);
        mBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                float newPaddingBottomValue = mPaddingBottomValue * (1-slideOffset);
                mRecyclerView.setPadding(0,0,0, (int) newPaddingBottomValue);
                Log.d("yanjin","newPaddingBottomValue = "+newPaddingBottomValue);
            }
        });
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if(id == R.id.mIv){
            Toast.makeText(App.getInstance(), "我能点到后面的控件哦", Toast.LENGTH_SHORT).show();
        }
    }
}

这里就处理了问题列表里面提到的recycleview显示不足的问题,盯着 mRecyclerView.setPadding相关代码看看就明白了。

然后就是我们的外部布局了,底部的布局需要上下拖动,且只能拖动顶部标题栏的话,我们要监听按下的位置是不是标题区域是的话打开滑动,不是的话就关闭。

public class MyRelativeLayout extends RelativeLayout {

    private BottomSheetBehavior mBehavior;
    private int length;

    public MyRelativeLayout(Context context) {
        this(context, null);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        length = Utils.dp2px(50f);//50dp对应着标题的高度
    }

    public void setBehavior(BottomSheetBehavior mBehavior) {
        this.mBehavior = mBehavior;
    }

    //true就是拦截  false  就是不拦截

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int y = (int) event.getY();
            if(length < y){
                if (mBehavior != null) {
                    mBehavior.setDraggable(false);//如果手指按下的Y值在列表里面,就不要dialog移动,这样就会把事件给recycle
                }
            }
        }else if(event.getAction() == MotionEvent.ACTION_UP){
            if (mBehavior != null) {
                mBehavior.setDraggable(true);//手指抬起时一定要设置回可拖动
            }
        }
        return super.dispatchTouchEvent(event);
    }

}

有朋友会问,那我能不能反过来,我先初始的时候设置setDraggable为false,然后在dispatchTouchEvent反向设置?答案是不行,我尝试过了,有兴趣的朋友可以试试,再读读源码。
其余的adapter代码,条目布局就不加上了。

你可能感兴趣的:(Android 记录一下BottomSheet的Behavior案例)