从ListView的滑动删除了解事件分发机制与冲突
来源:互联网 发布:手机淘宝图片保存位置 编辑:程序博客网 时间:2024/06/10 09:49
ListView滑动删除手势:
- item 从右向左滑动
- item 内部点击事件
事件分发过程中的主要方法:
boolean dispatchTouchEvent(MotionEvent ev)
:当事件能够传递到View时,那么该View的dispatchTouchEvent方法就会被调用,返回结果表示是否消耗当前事件boolean onInterceptTouchEvent(MotionEvent ev)
:在dispatchTouchEvent方法内调用,判断是否拦截某个事件,如果拦截,事件将不会再向下一层传递boolean onTouchEvent(MotionEvent ev)
:当onInterceptTouchEvent拦截事件后调用该方法,用来进行对应事件的处理上述三个方法的关系下面的伪代码解释的比较清楚:
public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = false; if(onInterceptTouchEvent(ev){ consume = onTouchEvent(ev); }else{ consume = child.dispathcTouchEvent(ev); } return consume;}
分析滑动删除功能
事件的传递过程主要看是否消费事件。根据滑动删除功能从右向左的滑动的触摸事件分析一下事件分发:
- 用户点击屏幕准备滑动item按钮时会产生一个ACTION_DOWN事件
- ACTION_DOWN事件传递到ListView时,ListView不消费、不拦截,记录初始位置,继续向下传递到自定义滑动item
- item 接收到ACTION_DOWN事件时,记住初始位置,用来后续测量滑动速度与距离
- 用户滑动时,传递一系列的ACTION_MOVE事件
- ACTION_MOVE事件传递到ListView时,ListView判断滑动方向,看是否向下s传递滑动,如果滑动方向不是从右向左,则不向下继续传递,如果是,则继续向下传递
- item接收到ACTION_MOVE事件时,判断滑动速度,滑动View
上述就是滑动事件的大概流程,下面分析一下具体的代码:
自定义 ListView
public class SlideListView extends ListView { private SlideItemLayout mCurrentItemView; /** * 记录之前滑动的位置 */ private int prePosition = -1; public SlideListView(Context context) { super(context); } public SlideListView(Context context, AttributeSet attrs) { super(context, attrs); } public SlideListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 测量,主要处理 ListView 在 ScrollView 等试图中的高度问题 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //当之前有item滑动过,再次滑动另一item时重置前一个item int position = pointToPosition((int) ev.getX(), (int) ev.getY()); if (position >= 0 && position != prePosition) { View currentItemView = getChildAt(position - getFirstVisiblePosition()); if (mCurrentItemView != null) { mCurrentItemView.reset(); } mCurrentItemView = (SlideItemLayout) currentItemView; prePosition = position; } break; case MotionEvent.ACTION_MOVE: //当设置状态为不能启用时不再向下传递滑动事件 if (!isEnabled()) { return true; } break; } return super.onInterceptTouchEvent(ev); }}
自定义item
public class SlideItemLayout extends ViewGroup { private float MAX_SLIDE_SPEED = 1000f; //最大滑动速度 private float deleteWidth; public SlideItemLayout(Context context) { super(context); } public SlideItemLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SlideItemLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); // 计算自定义的ViewGroup中所有子控件的大小 measureChildren(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureSize(widthMode, widthSize), measureSize(heightMode, heightSize)); } /** * 测量高度与宽度 * * @param mode * @return */ private int measureSize(int mode, int s) { int size = 0; switch (mode) { case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: size = s; break; } return size; } @Override protected void onLayout(boolean change, int l, int t, int r, int b) { int right = 0; int size = getChildCount(); //获取删除按钮的宽度 deleteWidth = getChildAt(size - 1).getMeasuredWidth(); for (int i = 0; i < size; i++) { View view = getChildAt(i); int childHeight = view.getMeasuredHeight(); int chileWidth = view.getMeasuredWidth(); view.layout(right, 0, right + chileWidth, childHeight); right += chileWidth; } } private float startX = 0; private float endX = 0; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: startX = ev.getX(); break; case MotionEvent.ACTION_MOVE: if (slideSpeed(ev) >= MAX_SLIDE_SPEED) { return true; } break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: endX = event.getX(); if (endX - startX < 0 && startX - endX <= deleteWidth) { //从右向左滑动 scrollTo((int) (startX - endX), 0); } break; case MotionEvent.ACTION_UP: endX = event.getX(); if (startX - endX < deleteWidth / 2) { scrollTo(0, 0); } else { scrollTo((int) deleteWidth, 0); } releaseVelocityTracker(); break; case MotionEvent.ACTION_CANCEL: endX = event.getX(); if (startX - endX < deleteWidth / 2) { scrollTo(0, 0); } else { scrollTo((int) deleteWidth, 0); } releaseVelocityTracker(); break; } return super.onTouchEvent(event); } private VelocityTracker mVelocityTracker; /** * 计算侧滑速度 * * @param event * @return */ private float slideSpeed(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, MAX_SLIDE_SPEED); return velocityTracker.getXVelocity(); } /** * 释放 VelocityTracker */ private void releaseVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.clear(); mVelocityTracker.recycle(); mVelocityTracker = null; } } /** * 返回到初始状态 */ public void reset() { scrollTo(0, 0); }}
具体实现效果
注:本文参考《Android开发艺术探索》—— 任玉刚
0 0
- 从ListView的滑动删除了解事件分发机制与冲突
- 通过事件分发机制处理ListView与ScrollView滑动冲突
- Android事件分发机制与滑动冲突
- 事件分发机制与滑动冲突
- Android View的事件分发机制与滑动冲突解决方案
- 利用事件分发机制解决ScrollView嵌套ListView滑动冲突
- Scrollview嵌套listview利用事件分发机制解决滑动冲突
- 从Listview与Button点击事件冲突看安卓点击事件分发机制
- Android滑动冲突与事件分发机制浅析
- Android 滑动冲突,事件分发机制的详解
- Android View事件分发机制及View的滑动冲突
- Android事件分发机制及滑动冲突处理的几篇博文
- Android View的事件分发机制和滑动冲突解决方案
- Android View的事件分发机制和滑动冲突解决方案
- Android View的事件分发机制和滑动冲突解决方案
- Android View的事件分发机制和滑动冲突解决
- 【Android View事件分发机制】滑动冲突
- Android事件分发机制、滑动冲突解决
- 124.Longest Consecutive Sequence-最长连续序列(中等题)
- SQL Server 远程连接问题
- 【算法设计与分析基础】蛮力法解决旅行商问题
- redis安装
- Java本身的排序函数如何调用
- 从ListView的滑动删除了解事件分发机制与冲突
- Java如何将数组转换为ArrayList(ArrayList和数组间的相互转换)
- Android面试题——Activity
- Count Numbers with Unique Digits
- Android面试题——Service
- 使用ViewPager和Fragment同时实现点击底部Tab切换和手势滑动切换Fragment
- linux服务器搭建solr服务
- 2017年搜狗校招Java研发笔试编程题
- 在Ubuntu Server 16.04 LTS下安装VMware Tools