Android 固定式底部上滑抽屉view
1、自定义view BottomDrawerLayout
/*** 作者:created by meixi* 邮箱:15913707499@163.com* 日期:2018/12/10 11*/public class BottomDrawerLayout extends ViewGroup {private static final String TAG = "BottomDrawerLayout";private View mDrawerView;private View mBottomView;private View mRotateView;private ViewDragHelper mDragHelper;private float mInitialX;private float mInitialY;private int mTouchSlop;private int mCurTop=-1;private int mBottomHeight;private int mDrawerHeight;private int mParentHeight;private float mDragOffset = 1;private boolean isUnderBottomView = false;private boolean isUnderDrawerView = false;private OnDrawerStatusChanged onDrawerStatusChanged;public BottomDrawerLayout(Context context) {super(context);init(context);}public BottomDrawerLayout(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public BottomDrawerLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context) {mDragHelper = ViewDragHelper.create(this, 1.0f,new DragerCallBack());mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();}public void setOnDrawerStatusChanged(OnDrawerStatusChanged onDrawerStatusChanged) {this.onDrawerStatusChanged = onDrawerStatusChanged;}public void switchDrawer() {if(mDragOffset<1){minimize();}else{maximize();}}private class DragerCallBack extends ViewDragHelper.Callback{//从底部到顶部的顺序遍历子view@Overridepublic int getOrderedChildIndex(int index) {int childCount = BottomDrawerLayout.this.getChildCount();int newIndex = childCount - index -1;return newIndex;}@Overridepublic boolean tryCaptureView(View child, int pointerId) {return child == mDrawerView;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) { // Log.d(TAG, "clampViewPositionHorizontal " + left + "," + dx); // final int leftBound = getPaddingLeft(); // final int rightBound = getWidth() - mBottomView.getWidth() - leftBound; // //坐标系三种情况 // final int newLeft = Math.min(Math.max(left, leftBound), rightBound); // // return newLeft;return super.clampViewPositionHorizontal(child, left, dx);}//要想上下拖动必须重写此方法@Overridepublic int clampViewPositionVertical(View child, int top, int dy) { // Log.d(TAG, "clampViewPositionVertical " + top + "," + dy);final int topBound = getHeight() - mDrawerView.getMeasuredHeight() - mBottomView.getHeight();final int bottomBound = getHeight() - mBottomView.getHeight();final int newTop = Math.min(Math.max(top, topBound), bottomBound);return newTop;}@Overridepublic void onViewCaptured(View capturedChild, int activePointerId) {super.onViewCaptured(capturedChild, activePointerId);}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {// Log.i(TAG, "onViewReleased:" + "xvel:" + xvel + ",yvel:" + yvel);//yvel Fling产生的值,yvel > 0 则是快速往下Fling || yvel < 0 则是快速往上Flingint top = mParentHeight - mDrawerHeight - mBottomHeight;if (yvel > 0 || (yvel == 0 && mDragOffset > 0.5f)/* 后面这个小括号里判断处理拖动之后停下来但是未松手的情况 */) {top += mDrawerHeight;}mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);invalidate();//important 不加,就不会刷新View的位置}@Overridepublic void onViewDragStateChanged(int state) {super.onViewDragStateChanged(state);}@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {mCurTop = top;mDragOffset = ((float) top -(mParentHeight - mDrawerHeight - mBottomHeight))/ mDrawerHeight; // Log.d(TAG, "onViewPositionChanged: mDragOffset:" + mDragOffset);//旋转与透明跟随效果mDrawerView.setAlpha(1-mDragOffset); // mRotateView.setRotation((1-mDragOffset)*180);requestLayout();if (onDrawerStatusChanged != null) {onDrawerStatusChanged.onChanged(mParentHeight,top);}// if(onDrawerStatusChanged !=null){ // if(mDragOffset == 0 || mDragOffset == 1){ // onDrawerStatusChanged.onChanged(mParentHeight,top); // } // }}}public interface OnDrawerStatusChanged{void onChanged(int parentHeight, int drawerTop);}public void maximize(){smoothSlideTo(0.0f);}public void minimize(){smoothSlideTo(1.0f);}private boolean smoothSlideTo(float slideOffset) {final int topBound = mParentHeight - mDrawerHeight - mBottomHeight;int y = (int) (topBound + slideOffset * mDrawerHeight);if(mDragHelper.smoothSlideViewTo(mDrawerView, mDrawerView.getLeft(), y)){ViewCompat.postInvalidateOnAnimation(this);return true;}return false;}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {int act = MotionEventCompat.getActionMasked(event); // final int action = event.getAction();switch (act) {//由于很多情况不能拦截事件,这种时候系统不会调用onTouchEvent()// 手动把事件传递给mDragHelper.processTouchEventcase MotionEvent.ACTION_DOWN:mInitialX = event.getX();mInitialY = event.getY();//Feed the down event to the detector so it has// context when/if dragging begins // mDetector.onTouchEvent(event);mDragHelper.processTouchEvent(event);isUnderBottomView = mDragHelper.isViewUnder(mBottomView, (int)mInitialX, (int)mInitialY);isUnderDrawerView = mDragHelper.isViewUnder(mDrawerView, (int)mInitialX, (int)mInitialY);break;case MotionEvent.ACTION_POINTER_DOWN:mDragHelper.processTouchEvent(event) ;break;case MotionEvent.ACTION_POINTER_UP:mDragHelper.processTouchEvent(event) ;break;case MotionEvent.ACTION_MOVE:final float x = event.getX();final float y = event.getY();final int yDiff = (int) Math.abs(y - mInitialY);final int xDiff = (int) Math.abs(x - mInitialX);//Verify that either difference is enough to be a dragif ((yDiff > mTouchSlop || xDiff > mTouchSlop) && (isUnderBottomView || isUnderDrawerView) ){//Start capturing eventsreturn true;}break;}//父类是viewgroup,返回的falsereturn super.onInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {mDragHelper.processTouchEvent(event);//down事件返回false,让其底部的平行层级的view能够接收到点击事件switch (event.getAction()) {case MotionEvent.ACTION_DOWN:return false;case MotionEvent.ACTION_UP:return false;//只有当手指达到拖动阈值时this才确定消耗此系列事件//若未达到阈值也返回true,则与其平行的view不会收到click事件case MotionEvent.ACTION_MOVE:final float x = event.getX();final float y = event.getY();final int yDiff = (int) Math.abs(y - mInitialY);final int xDiff = (int) Math.abs(x - mInitialX);//Verify that either difference is enough to be a dragif ((yDiff > mTouchSlop || xDiff > mTouchSlop) && (isUnderBottomView || isUnderDrawerView) ){//Start capturing eventsreturn true;}break;}return false;}@Overrideprotected void onFinishInflate() {super.onFinishInflate();mBottomView = findViewById(R.id.layout_bottom_bar);mDrawerView = findViewById(R.id.layout_price_detail);// mRotateView = findViewById(R.id.img_spread_out);mBottomView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {maximize();}});mDrawerView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {minimize();}});}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {measureChildren(widthMeasureSpec,heightMeasureSpec);super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mParentHeight = this.getHeight();mBottomHeight = mBottomView.getMeasuredHeight();mDrawerHeight = mDrawerView.getMeasuredHeight(); // Log.d(TAG, "onLayout: drawHeight:"+drawHeight);mBottomView.layout(l,mParentHeight - mBottomHeight,r,b);if(mCurTop == -1){mCurTop = mParentHeight - mBottomHeight;}mDrawerView.layout(l,mCurTop,r,mCurTop + mDrawerHeight);}@Overridepublic void computeScroll() {if(mDragHelper.continueSettling(true)){ViewCompat.postInvalidateOnAnimation(this);}} }
layout布局中使用这个自定义抽屉view即可,第一个LinearLayout是抽屉内容,第二个LinearLayout是固定底部把手
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent" android:layout_height="match_parent"><com.tianxin.shanghuact.BottomDrawerLayoutandroid:id="@+id/bottom_drawer_layout"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/layout_price_detail"android:layout_width="match_parent"android:background="@color/colorPrimary"android:orientation="horizontal"android:layout_height="180dp"></LinearLayout><LinearLayoutandroid:id="@+id/layout_bottom_bar"android:layout_width="match_parent"android:background="@color/transparent"android:orientation="horizontal"android:layout_height="40dp"></LinearLayout></com.tianxin.shanghuact.BottomDrawerLayout></RelativeLayout>
Android 固定式底部上滑抽屉view相关推荐
- Android 底部上拉抽屉view
module链接:https://download.csdn.net/download/meixi_android/10839835 接入module方法:https://blog.csdn.net/ ...
- android底部上滑锁屏
概述 各种测试,各种查资料,总算解决了底部上滑锁屏功能的实现.一个底部三大金钢折腾死个人. 最后借助的还是AccessibilityService实现.因为我想实现的底部导航栏一定要显示在屏幕最底端, ...
- html5移动端底部效果,spring mvc +HTML5实现移动端底部上滑异步加载更多内容分页效果...
代码实现 1).前端代码: 前端代码需要用到jquery和zepto,大家在网上自己下载,下面是页面的代码: contentType="text/html; charset=UTF-8&qu ...
- Android 自定义底部上拉控件的实现
前言 又到了新的一月,今天提供一个Android自定义底部上拉布局的实现,起因是自己在项目中需要实现这样一个控件,干脆自己写一个练练手. 写完了觉得能想到的需求都基本有了(可能会有其它需求,不过基本上 ...
- 从底部上滑失灵_iPad 上这 20 个快捷操作,真正帮你提高生产力!
Hello 这里是一周进步,更多干货欢迎阅读:一周进步 · 2020半年文章精选 文 / 一周进步 · Cherry 如果你是想把 iPad 变成生产力工具(而不是盖泡面),熟悉使用界面的基础操作,就 ...
- 安全锁界面,防止底部上滑触发人脸解锁与绘制图案锁冲突
原生在KeyguardSecurityContainer.java中,当滑动至安全锁界面时,如果设置了人脸解锁,会上滑再次触发人脸解锁. 此时若是图案解锁,会时有发生图案锁绘制与上滑触发人脸解锁冲突的 ...
- android 上滑隐藏view,Android CoordinatorLayout + AppBarLayout(向上滚动隐藏指定的View)
在新的Android Support Library里面,新增了CoordinatorLayout, AppBarLayout等. 实现的效果: 向下滚动RecylerView,Tab会被隐藏,向上滚 ...
- 从底部上滑失灵_宝鸡终于也有超火的高空玻璃水滑啦!就在玉池公社!8月10日见~...
夏天一定要去有"水"的地方 去哪里呢?小宝妹告诉你! 玉池公社千米玻璃水滑 这个夏季即将来袭 快来让激情燃烧一会儿! 宝鸡玉池玻璃水滑来了! 高空玻璃水滑采用钢结构框架 透明钢化玻 ...
- 从底部上滑失灵_雷达液位计测量液位失灵的检查处理方法
1.检查供电是否正常. 2.检查通讯是否正常.通过安装了雷达调试软件的手提电脑.FBM(双向调制/解调器)接入FCU2160(现场通讯单元),可以在操作界面上读取雷达的所有数据,发射波.反射波强度,雷 ...
最新文章
- 美国邮政署将展开测试自驾卡车运输服务
- python3中的int类型占64位_在windows 10 64位计算机中,默认情况下,numpy数组数据类型将以int32形式出现...
- JavaScript instanceof 运算符深入剖析
- shell-4.bash的变量:用户自定义变量
- Linux驱动修炼之道-内存映射
- Redis集群的重启
- oracle批处理参数调用,bat调用jar包并传入多个参数
- ios textview间距_iOS 设置TextView控件内容行间距
- 肖仰华 | 基于知识图谱的问答系统
- 4-1MapReduce原理
- 解析linux中的vfs文件系统机制,解析Linux中的VFS文件系统机制
- Python稳基修炼的经典案例9(计算机二级、初学者必会turtle库例题)
- 快速开发框架工作笔记001---项目开发中整理_整合好的_springcloud快速开发框架_springcloud框架_springcloud架构
- 私钥、公钥、数字签名、数字证书、HTTPS
- Java 多线程详解(五)------线程的声明周期
- boost::asio c++ 网络编程socket通信一个简单例子
- Silverlight 2应用程序中XAP文件揭秘
- 2 月全国程序员工资统计 + 大厂新入职员工职级对应表
- TOM邮箱|国内适合商务人士的邮箱是什么邮箱
- 教你用优化视频的方法提高视频的质量