Android基础知识 View事件机制

本文详细探讨了Android中View的坐标体系,包括原点位置、View常用属性和mTouchSlop。还介绍了VelocityTracker的速度追踪,GestureDetector的手势检测以及Scroller的弹性滑动。此外,讲解了View滑动的多种方式,如使用ScrollTo/ScrollBy、动画和改变布局参数。文章进一步阐述了View的事件分发机制,包括dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent的方法和规则,以及处理滑动冲突的策略和解决方法。
摘要由CSDN通过智能技术生成

View的坐标体系

1、原点在屏幕左上角
2、View常用属性
属性 含义 描述
mLeft、mTop、mRight、mBottom Parent的左上角为参考 原点
width = mRight - mLeft
height = mBottom - mTop
getTranslationX()
getTranslationY()
位移 默认值是0
mX、mY mX = mLeft + getTranslationX();
mY = mTop + getTranslationY();
View左上角相对于Parent容器的坐标
mScrollX 相对View的左边缘,在X轴方向的偏移量
mScrollY 相对View的上边缘,和Y轴方向的偏移量
MotionEvent.ACTION_DOWN 手指按下屏幕
MotionEvent.ACTION_MOVE 手指在屏幕移动
MotionEvent.ACTION_UP 手指离开屏幕
event.getX()
event.getY()
手指 相对当前View左上角 的 x、y坐标
event.getRawX()
event.getRawY()
手指 相对于手机屏幕左上角 的x、y坐标
3、mTouchSlop

系统能识别的被认为是 滑动的最小距离
手指在屏幕移动距离 小于 mTouchSlop,不认为是滑动

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

处理滑动时,用这个常量过滤未达到这个临界值的移动行为

4、VelocityTracker 速度追踪

追踪手指滑动的速度,包括水平和竖直方向的速度

  • 在 View 的 onTouchEvent 方法,追踪当前单击事件的速度

    VelocityTracker velocityTracker = new VelocityTracker.obtain();
    velocityTracker.addMovement(event);
    
  • 获取当前滑动速度

    //计算速度 1000 表示计算1000ms内手指滑过的像素数
    velocityTracker.computeCurrentVelocity(1000);
    int xVelocity = (int) velocityTracker.getXVelocity();
    int yVelocity = (int) velocityTracker.getYVelocity();
    

    速度指一段时间内手指滑过的像素数。
    速度可以为负数,从右往左滑,水平方向速度为负值。
    速度 = (终点位置 - 起点位置) / 时间段

  • 不需要使用时,重置并回收内存

    velocityTracker.clear();
    velocityTracker.recycle();
    
5、GestureDetector

手势检测,辅助检测用户的单击、滑动、长按、双击等行为。

  • 创建GestureDetector 对象,并实现 OnGestureListener 接口

    根据需要可以实现 OnDoubleTapListener 监听双击行为
    //手势监听
    GestureDetector detector = new GestureDetector(GestureDetector.OnGestureListener);
    //监听双击行为
    detector.setOnDoubleTapListener(GestureDetector.OnDoubleTapListener);
    //解决长按屏幕后无法拖动的现象
    detector.setIsLongpressEnabled(false);
    
  • View 的 onTouchEvent 中添加实现

    boolean consume = detector.onTouchEvent(event);
    return consume;
    
  • 监听方法介绍
    1) OnGestureListener的方法

    方法 描述
    onDown 手指触摸屏幕的瞬间,由1个ACTION_DOWN 触发
    onShowPress 手指轻触屏幕尚未松开和拖动,由1个ACTION_DOWN触发
    和onDown的区别是,它是没有松开和拖动的状态
    onSingleTapUp 手指轻触屏幕后松开,伴随1个ACTION_UP触发,单击行为
    onScroll 手指按下屏幕并拖动,由1个ACTION_DOWN、多个ACTION_MOVE 触发,拖动行为
    onLongPress 长按屏幕不放
    onFling 按下屏幕、快速滑动后松开
    由1个ACTION_DOWN,多个ACTION_MOVE、1个ACTION_UP触发
    快速滑动行为

    2) OnDoubleTapListener的方法

    方法 描述
    onDoubleTap 双击。由两次连续的单击组成。不会与 onSingleTapConfirmed 共存
    onSingleTapConfirmed 严格的单击行为
    与 onSingleTapUp 的区别:如果触发了 onSingleTapConfirmed
    那么后面不可能再紧跟另一个单击行为。
    只可能是单击,不可能是双击中的一次单击
    onDoubleTapEvent 表示发生了双击行为,
    在双击期间,ACTION_DOWN、ACTION_MOVE、ACTION_UP 都会触发此回调。
6、Scroller 弹性滑动对象

用于实现View 的弹性滑动

View滑动的几种方式,使用 ScrollTo/ScrollBy、使用动画、改变布局参数

1、scrollTo/scrollBy 瞬间完成,没有过渡效果

scrollTo/scrollBy,滑动的是View的内容,并不能滑动View本身。

  • scrollBy(x, y) 相对当前位置的滑动
    内部调用 scrollTo 方法,scrollTo(mScrollX + x, mScrollY + y)

  • scrollTo(x, y) 基于所传递参数的绝对滑动

【滑动时,mScrollX,mScrollY的改变规则】
View边缘:指View的位置,由四个顶点组成
View内容边缘:指View中的内容的边缘

mScrollX:== View左边缘与View内容左边缘,在水平方向的距离
mScrollY:== View上边缘与View内容上边缘,在竖直方向的距离

scrollTo、scrollBy,只能改变View内容的位置,不能改变View在布局中的位置

当View左边缘在View内容左边缘的右边时,mScrollX为正值,反之为负值
(从左向右滑动,mScrollX为负值,反之为正值)

当View上边缘在View内容上边缘的下边时,mScrollY为正值,反之为负值
(从上往下滑动,mScrollY为负值,反之为正值)

2、使用动画

操作 View的 translationX 和 translationY 属性。

属性动画,改变的是View的属性
ObjectAnimator.ofFloat(targetView, “translationX”, 0, 100).setDuration(100).start();

View动画操作的是View的影像
View动画,要把fillAfter设置为true,否则在动画结束后会恢复到动画前状态

3、改变布局参数

改变 LayoutParams

View滑动实现 实现方式
ScrollTo/ScrollBy scrollTo/scrollBy,滑动的是View的内容,并不能滑动View本身
scrollBy(x, y) 相对当前位置的滑动
内部调用 scrollTo 方法,scrollTo(mScrollX + x, mScrollY + y)
scrollTo(x, y) 基于所传递参数的绝对滑动
使用动画 属性动画,改变View的属性
ObjectAnimator.ofFloat(targetView, “translationX”, 0, 100).setDuration(100).start();

View动画操作View的影像
View动画,要把fillAfter设置为true,否则在动画结束后会恢复到动画前状态
改变布局参数

弹性滑动的原理及实现

1、使用Scroller
Scroller mScroller = new Scroller(context);	
//缓慢滚动到指定位置
private void smoothScrollTo(int destX, int destY) {
	int scrollX = getScrollX();
	int delta = destX - scrollX;
	/* 1000ms内滑向destX,效果是慢慢滑动
	 * startScroll()只是保存了传递的几个参数
	 * 参数一:滑动的起点x
	 * 参数二:滑动的起点y
	 * 参数三:要滑动的距离dx
	 * 参数四:要滑动的距离dy
	 * 参数五:滑动时间
	 */
	mScroller.startScroll(scrollX, 0, delta, 0, 1000);
	invalidate();//重绘,触发onDraw(),onDraw中会调用computeScroll()
}

@Override
public void computeScroll() {
	/* computeScrollOffset()
	 * 这个方法会根据时间的流逝百分比,计算当前的scrollX和scrollY的值,
	 * 返回true,表示滑动还未结束,false表示滑动已结束
	 */			
	if(mScroller.computeScrollOffset()) {
		//获取 mScroller当前的scrollX,scrollY,通过scrollTo方法实现滑动到新位置
		scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
		postInvalidate();
	}
}

滑动执行过程:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值