View的事件体系

来源:互联网 发布:mac暗影格斗2修改 编辑:程序博客网 时间:2024/05/20 16:43

一、View的位置参数

View的位置分别包含4大属性:top、left、right、bottom,他们都是相对于父控件而言。控件的宽度和长度为:width=right-left height=bottom-top

二、MotionEvent和TouchSlop

1、MotionEvent表示点击事件的X和Y坐标。分别有getX()、getY()表示相对于父控件的坐标.getRawX()和getRawY()表示相对于屏幕的坐标
2、TouchSlop表示系统识别为滑动的最小距离。通过ViewConfiguration.get(getContext().getScaledTouchSlop())来获取当前手机的值

三、VelocityTracker

用于表示单位时间内手指的滑动速度。获取步骤如下:
1、通过在onTouchEvent()方法中追踪当前事件的速度:
VelocityTracker tracker=VelocityTracker.obtain();
tracker.addMovement(event)
2、接着获取当前的速度。首先要通过computeCurrentVelocity()来计算当前的速度。
tracker.computeCurrentVelocity()
xVelocity=tracker.getXVelocity()
yVelocity=tracker.getYVeloctiy();
3、当不使用时收回
tracker.clear()
tracker.recycle()

四、GestureDetector

用于检查用户的手势包括单击、滑动、长按等
1、初始化
GestrueDetector detector=new GestrueDetector();
dectector.setIsLongPressEnable(false);//用于解决长按后无法拖动的情况
2、设置监听器
detector.setOnGestureLisenter()
3、开始检测手势
通过监听触控事件即可监听手势
detector.onTouchEvent()

五、Scroller的作用

一般情况下ScrollTo和ScrollBy是瞬时的滑动到指定位置。如果要使控件有过渡的完成滑动需要通过Scroller类的协助。
一般通过scoller.startScroll开始启动滑动,然后他会不断的调用computeScroll来更新位置代码如下:
mScroller.startScroll(getScrollX(), 0, dx, 0, 500);//开始滑动
/**
更新控件位置
**/

 @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();        }    }

六、View的滑动

View的滑动一般有以下几种方式:
1、通过ScrollTo和Scrollby
它实际上改变的的View的内容的的位置,而不是改变他布局的位置。
ScrollTo和Scrollby改变的实际上是mScrollX和mScrollY.它们的坐标体系是上正,下负。左正,又负。
2、使用动画
在 android 3.0上增加了translationX、translationY属性。通过改变他们即可改变他们的位置。若要兼容到2.2则需要引入nineolandroid兼容库。
动画并不是真正的改变控件的位置他是一种假象。实际位置并没有变化。
3、改变布局参数
通过改变LayoutParam的margin也可以达到滑动的效果

七、View的事件拦截机制

1、事件的分发一般由三个函数完成:1)dispatchTouchEvent() 2)onInterceptTouchevent() 3)onTouchEvent();
2、事件分发的一般顺序:mo1)首先调用dispatchTouchEvent() 2)调用onInterceptTouchevent()判断是否拦截该事件 若:不拦截则直接传递给子View调用他的dispatchTouchEvent() 3)若拦截则判断是否有onTouchListener 若有且返回true则不会继续传递 4)若返回false则调用ontouchEvent()
3、注意点
1)一旦拦截则不会再次的调用onInterceptTouchEvent()
2)若View不消耗Action_Down事件那么同一事件序列将不会交给他处理
3)若不消耗Action_Down的事件那么这这个事件会消失,但控件还是会继续收到后续事件,父控件的onTouchEvent并不会被调用。Activity会处理点击事件
4)View没有OnIntercepterTouchEvent事件
5)View的默认会消耗事件的,除非Clickabe为false;
6)子元素可以通过requestDisallowwInterceptTouchEvent()事件来干预父元素
7)若子元素onTouchEvent返回false 那么父元素的onTouchEvent也会被调用
8)View在不可用的状态下也会消耗点击事件
9)当View为Clickable时既会消耗点击事件
10)设置有onClickLisnter时clickalbe会默认为True

八、事件分发的源码解析

Actvity(dispatchTouchEvent())–>PhoneWindow(superDispatchTouchEvent())–>DecorView(superDispatchTouchEvent())–>ViewGroup(dispatchTouchEvent())
当传递到Viewgroup层后ViewGoup首先会调用onIntercpetTouchEvent()来判断是否拦截事件,
1)若要拦截则以后都不会再次调用onIntercpetTouchEvent()——>若在ViewGroup中设置了OnToucherListener则会调用onTouch()事件,–》若onTouch()返回true则停止传递若返回false则调用onTouchEvent–>在onTouchEvent中若有onClickListener则会吸收该事件。
2)若onInterceptTouchEvent()不拦截则会调用子View的dispatchTouchEvent;

九、滑动冲突

滑动冲突解决方案一般分为外部拦截法和内部拦截法。
1、外部拦截即在父控件根据实际情况处理是否拦截,若拦截则不会再传导给子控件
在onInterceptTouchEvent中决定是否拦截。若是则返回true,若否则返回false
2、内部拦截即在子控件中根据情况来处理是否允许父控件进行拦截。
1)在父控件的onInterceptTouchEvent中出Action_Down外其余都返回true
2)在子控件中dispatchTouchEvent方法Action_Down中调用parent.requestDisallowInterceptTouchEvent(true);
在Action_Move中若要父控件拦截则调用parent.requestDisallowIntercptTouchEvent(false);

0 0