android汽车之家顶部滑动菜单,Touch事件分发 - 汽车之家折叠列表

1.ViewDragHelper介绍

900667412f39

效果图.gif

1.1创建

mViewDragHelper= ViewDragHelper.create(this, mDragHelperCallback);

1.2实现拖动

@Override

public boolean onTouchEvent(MotionEvent event) {

mViewDragHelper.processTouchEvent(event);

return true;

}

//拖动我们的子view

private ViewDragHelper.Callback mDragHelperCallback=new ViewDragHelper.Callback() {

@Override

public boolean tryCaptureView(@NonNull View child, int pointerId) {

//指定子view是否可以拖动

//代表都可以

return true;

}

@Override

public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {

//水平拖动移动的位置

return left;

}

@Override

public int clampViewPositionVertical(@NonNull View child, int top, int dy) {

//垂直拖动移动的位置

return top;

}

};

2.效果分析实现

2.1 后面不能拖动

2.2 列表只能垂直拖动

2.3 垂直拖动的范围只能是后面菜单 View 的高度

获取控件的宽高一定是要在测量完毕之后才能去拿,也就是要在onMeasure()之后

2.4 手指松开的时候两者选其一,要么打开要么关闭

900667412f39

效果图.gif

public class VerticalDragListView extends FrameLayout {

//这是系统给我们写好的一个工具类

private ViewDragHelper mViewDragHelper;

private View mDragListView;

// 后面菜单的高度

private int mMenuHeight;

public VerticalDragListView(Context context) {

this(context, null);

}

public VerticalDragListView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public VerticalDragListView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mViewDragHelper = ViewDragHelper.create(this, mDragHelperCallback);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

mViewDragHelper.processTouchEvent(event);

return true;

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

int childCount = getChildCount();

if (childCount != 2) {

throw new RuntimeException("VerticalDragListView只能包含两个子布局");

}

mDragListView = getChildAt(1);

}

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

if(changed){

View menuView = getChildAt(0);

mMenuHeight = menuView.getMeasuredHeight();

}

}

/**

* 拖动我们的子view

*/

private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {

@Override

public boolean tryCaptureView(@NonNull View child, int pointerId) {

//指定子view是否可以拖动

//true代表都可以

// 2.1 后面不能拖动

return mDragListView == child;

}

// 2.2 列表只能垂直拖动

@Override

public int clampViewPositionVertical(@NonNull View child, int top, int dy) {

// 2.3 垂直拖动的范围只能是后面菜单 View 的高度

if (top <= 0) {

top = 0;

}

if (top >= mMenuHeight) {

top = mMenuHeight;

}

return top;

}

// 2.4 手指松开的时候两者选其一,要么打开要么关闭

@Override

public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {

Log.e("TAG", "yvel -> " + yvel + " mMenuHeight -> " + mMenuHeight);

Log.e("TAG", "top -> " + mDragListView.getTop());

if(releasedChild==mDragListView){

if(mDragListView.getTop()>mMenuHeight/2){

//打开

mViewDragHelper.settleCapturedViewAt(0,mMenuHeight);

}else{

mViewDragHelper.settleCapturedViewAt(0,0);

}

invalidate();

}

}

};

/**

* 响应滚动

*/

@Override

public void computeScroll() {

if(mViewDragHelper.continueSettling(true)){

invalidate();

}

}

}

将前面换成ListView分析事件的分发和拦截

900667412f39

效果分析.gif

主布局

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="200dp"

android:background="@color/colorPrimary"

android:gravity="center"

android:text="后面" />

android:id="@+id/list_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#FFFFFF" />

VerticalDragListView代码

public class VerticalDragListView extends FrameLayout {

//这是系统给我们写好的一个工具类

private ViewDragHelper mDragHelper;

private View mDragListView;

// 后面菜单的高度

private int mMenuHeight;

private boolean mMenuIsOpen;

public VerticalDragListView(Context context) {

this(context, null);

}

public VerticalDragListView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public VerticalDragListView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mDragHelper = ViewDragHelper.create(this, mDragHelperCallback);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

mDragHelper.processTouchEvent(event);

return true;

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

int childCount = getChildCount();

if (childCount != 2) {

throw new RuntimeException("VerticalDragListView只能包含两个子布局");

}

mDragListView = getChildAt(1);

}

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

if (changed) {

View menuView = getChildAt(0);

mMenuHeight = menuView.getMeasuredHeight();

}

}

/**

* 拖动我们的子view

*/

private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {

@Override

public boolean tryCaptureView(@NonNull View child, int pointerId) {

//指定子view是否可以拖动

//true代表都可以

// 2.1 后面不能拖动

return mDragListView == child;

}

// 2.2 列表只能垂直拖动

@Override

public int clampViewPositionVertical(@NonNull View child, int top, int dy) {

// 2.3 垂直拖动的范围只能是后面菜单 View 的高度

if (top <= 0) {

top = 0;

}

if (top >= mMenuHeight) {

top = mMenuHeight;

}

return top;

}

// 2.4 手指松开的时候两者选其一,要么打开要么关闭

@Override

public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {

Log.e("TAG", "yvel -> " + yvel + " mMenuHeight -> " + mMenuHeight);

Log.e("TAG", "top -> " + mDragListView.getTop());

if (releasedChild == mDragListView) {

if (mDragListView.getTop() > mMenuHeight / 2) {

//打开

mDragHelper.settleCapturedViewAt(0, mMenuHeight);

mMenuIsOpen = true;

} else {

mDragHelper.settleCapturedViewAt(0, 0);

mMenuIsOpen = false;

}

invalidate();

}

}

};

// 现象就是ListView可以滑动,但是菜单滑动没有效果了

private float mDownY;

@Override

public boolean onInterceptTouchEvent(MotionEvent event) {

// 菜单打开要拦截

if (mMenuIsOpen) {

return true;

}

//向下滑动拦截,不给listview处理

//父View拦截子View ,但是子 View 可以调这个方法

// requestDisallowInterceptTouchEvent 请求父View不要拦截,改变的其实就是 mGroupFlags 的值

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

mDownY=event.getY();

mDragHelper.processTouchEvent(event);

break;

case MotionEvent.ACTION_MOVE:

float moveY = event.getY();

if((moveY-mDownY)>0&&!canChildScrollUp()){

// 向下滑动 && 滚动到了顶部,拦截不让ListView做处理

return true;

}

break;

default:

break;

}

return super.onInterceptTouchEvent(event);

}

/**

* 参看SwipeRefreshLayout源码的canChildScrollUp

* 判断View是否滚动到了最顶部,还能不能向上滚

*/

@SuppressLint("ObsoleteSdkInt")

public boolean canChildScrollUp() {

if (android.os.Build.VERSION.SDK_INT < 14) {

if (mDragListView instanceof AbsListView) {

final AbsListView absListView = (AbsListView) mDragListView;

return absListView.getChildCount() > 0

&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)

.getTop() < absListView.getPaddingTop());

} else {

return ViewCompat.canScrollVertically(mDragListView, -1) || mDragListView.getScrollY() > 0;

}

} else {

return ViewCompat.canScrollVertically(mDragListView, -1);

}

}

/**

* 响应滚动

*/

@Override

public void computeScroll() {

if (mDragHelper.continueSettling(true)) {

invalidate();

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值