View的事件体系

3.1 View 的基础知识

3.1.1 什么是 View

View 是Android中所有控件的基类,View 是界面层控件的一种抽象,它代表一个控件,ViewGroup 也继承View,View可以是单个控件也可以是有多个控件组成的一组控件,形成了View树的结构。

3.1.2 View 的位置参数

主要由四个顶点来决定,分别对应top、left、right、bottom,这些坐标相对于View的父容器来说的,是相对坐标。View 的宽高和坐标关系
width = right - left
height = bottom - top
left = getLeft(),right = getRight() 以此类推。

从Android 3.0开始,View增加了额外参数,左上角坐标(x,y),左上角相对于父容器的偏移量(translationX,translationY,默认为0)。
x = left + translationX
y = right + translationY

3.1.3 MotionEvent和TouchSlop

  • MotionEvent 通过手指接触屏幕所产生的一系列事件
    • getX ,getY 返回的是相对于当前View左上角的x,y坐标。
    • getRawX,getRawY 返回的是相对于手机屏幕左上角的x,y坐标。
  • TouchSlop 系统识别出的被认为是滑动最小距离,常量,不同设备值可能不同
    • ViewConfiguration.get(getContext()).getScaledTouchSlop()即可获取这个常量。

3.1.4 VelocityTracker、GestureDetector、Scroller

  • VelocityTracker 速度追踪,用于追踪手指滑动过程中的速度(水平、竖直)

    • 单机速度
      VelocityTracker vt = VelocityTracker.obtion();
      vt.addMovement(event);
    • 滑动速度
      vt.computeCurrentVelocity(1000);
      int xVelocity = (int)vt.getXVelocity();
      int yVelocity = (int)vt.getYVelocity();

    1000ms内手指滑动的像素数,正值代表从左向右滑,负值代表从右向左滑。

  • GestureDetector 手势检测,辅助检测用户的单击,滑动,双击,长按等行为。
    • 监听长按行为
      GestureDetector gd = new GestureDetector(this);
      gd.setIsLongPressEnabled(false);
      boolean consume = gd.onTouchEvent(event);
      return consume;
  • Scroller 弹性滑动对象,用于View 的弹性滑动,实现过渡效果的滑动,在一定时间间隔内完成

3.2 View的滑动

3.2.1 使用scrollTo/scrollBy

scrollTo源码:

public void scrollTo(int x, int y) {
    if (mScrollX != x || mScrollY != y) {
        int oldX = mScrollX;
        int oldY = mScrollY;
        mScrollX = x;
        mScrollY = y;
        invalidateParentCaches();
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);
        if (!awakenScrollBars()) {
            postInvalidateOnAnimation();
        }
    }
}

scrollBy源码:

 public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

mScrollX总等于View的左边缘和View内容左边缘水平方向的距离,这两个方法只能改变View内容的位置,不能改变View在布局中的位置。

3.2.2 使用动画

  • 使用View动画 在xml中定义动画
  • 使用属性动画,代码书写
    ObjectAnimator.ofFloat(textview,"tanslationX",0,100).setDuration(100).start()
    View 动画并不能真正改变View的位置,保留新位置需要fillAfter属性设置为true,单击新位置无法触发onClick事件,属性动画不存在这个问题,但是Android 3.0以下无法使用属性动画,需要使用动画兼容库nineoldandroids来实现。

3.2.3 改变布局参数

  • 改变LayoutParams
    MarginLayoutParams params = button.getLayoutParams();
    params.width += 100;
    button.requestLayout();
    或者button.setLayoutParams(params);

3.4 View 的事件分发机制

3.4.1 点击事件传递规则

请看如下伪代码

 public boolean dispatchTouchEvent(MotionEvent ev) {
      boolean consume = false;  
      if (onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);
      } else {
        consume = child.dispatchTouchEvent(ev);
      }
        return consume;
    }

对于一个根ViewGroup来说,点击事件产生后dispatchTouchEvent被调用,onInterceptTouchEvent方法返回true,表示拦截当前事件,返回false,表示不拦截当前事件,当前事件会传递给它的子元素,子元素的dispatchTouchEvent方法会被调用。

public boolean dispatchTouchEvent(MotionEvent event) {  
    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) {  
        return true;  
    }  
    return onTouchEvent(event);  
}  

View处理点击事件时判断mOnTouchListener是否为null,不为null时,如果onTouch方法返回false,onTouchEvent()方法被调用,如果onTouchEvent()方法中设置OnClickListener,那么会被调用,返回true,onTouchEvent方法不会被调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值