美文网首页DialogAndroidViewAndroid
Android 记录一下BottomSheet的Behavior

Android 记录一下BottomSheet的Behavior

作者: 坑逼的严 | 来源:发表于2021-11-17 13:47 被阅读0次

    先看图:


    1637121451617.gif

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

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

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".sheetDialog.DragDialogActivity">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/holo_blue_light">
            <ImageView
                android:id="@+id/mIv"
                android:layout_width="300dp"
                android:layout_height="450dp"
                android:background="@color/black"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10dp"/>
        </RelativeLayout>
        <com.example.demo.sheetDialog.MyRelativeLayout
            android:id="@+id/mBottomSheetContent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:behavior_hideable="false"
            app:behavior_peekHeight="250dp"
            android:layout_gravity="bottom"
            android:background="@color/red"
            app:layout_behavior="@string/bottom_sheet_behavior">
            <com.google.android.material.tabs.TabLayout
                android:id="@+id/mTitleTab"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                app:tabGravity="start"
                app:tabMode="scrollable"/>
    
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/mRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@id/mTitleTab"
                android:nestedScrollingEnabled="false"/>
        </com.example.demo.sheetDialog.MyRelativeLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    

    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<RelativeLayout> 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<RelativeLayout> 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<RelativeLayout> 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

        本文链接:https://www.haomeiwen.com/subject/uqeltrtx.html