美文网首页
Android系统知识全览---View知识体系(2)---Vi

Android系统知识全览---View知识体系(2)---Vi

作者: 善笃有余劫 | 来源:发表于2018-08-19 20:56 被阅读22次

    View的事件体系

    • View的概念
    • View的事件
    • View的滑动事件
    • View事件分发机制
    • View的滑动冲突解决

    View的概念

    View是界面上控件的在代码层的抽象体现。所有控件继承于View基类,根据功能可以分为View和ViewGroup。其中ViewGroup表示控件组,可以放置控件View。

    View的属性参数

    View的位置属性:

    left、right、top、bottom、elevation

    image

    如图所示:

    • left:目标View的最左边和这个View所在父控件的最左边的距离,通过view.getLeft()方法获取;
    • right:目标View的最右边和这个View所在父控件的最左边的距离,通过view.getRight()方法获取;
    • top:目标View的最上边和这个View所在父控件的最上边的距离,通过view.getTop()方法获取;
    • bottom:目标View的最下边和这个View所在父控件的最上边的距离,通过view.getBottom()方法获取;
    • elevation:目标View的Z轴高度和这个View所在的父控件所在的Z轴高度的距离,通过view.getElevation()方法获取(这个属性是Android 5.0之后添加的新属性)。

    同理可以得出View.width=right-left,View.height=bottom-top

    translationX、translationY、translationZ

    这三个参数代表的是在动画或者滑动View的时候,View的当前位置相对于其原始位置平移的距离:

    translation 翻译; 译本; 转化; 转变;

    • translationX:在滑动过程中,View当前位置的最左边和这个View原始位置的最左边的距离,通过view.getTranslationX()方法获取;
    • translationY:在滑动过程中,View当前位置的最上边和这个View原始位置的最上边的距离,通过view.getTranslationY()方法获取;
    • translationZ:在动画过程中,View当前位置的Z轴高度和这个View原始Z轴高度的距离,通过view.getTranslationZ()方法获取(这个方法是Android 5.0之后添加的新方法)。

    x、y、z

    这三个参数代表的是View的当前位置相对于其父控件的距离:

    • x:目标View的当前位置的最左边和这个View所在父布局的最左边的距离,通过view.getX()方法获取;
    • y:目标View的当前位置的最上边和这个View所在父布局的最上边的距离,通过view.getY()方法获取;
    • z:目标View的当前位置的Z轴位置和这个View所在父布局的Z轴位置的距离,通过view.getZ()方法获取(这个方法是Android 5.0之后添加的新方法)。
        这三个参数和前面的几个参数的关系公式如下:
    x = left + translationX;
    y = top + translationY;
    z = elevation + translationZ;
    

    值得注意的是 View在平移动作,参考点是左上角 所以 所谓的移动距离也只能是相对于左上角坐标的变化。

    View的事件

    MotionEvent和TouchSlop

    View可以接受和处理类似点击 长按 双击等动作。这里有个MotionEvent可以接受处理。

    • ACTION_DOWN:手指刚刚触摸到屏幕时触发的事件;
    • ACTION_MOVE:手指在屏幕上移动的时候触发的事件;
    • ACTION_UP:手指从屏幕上抬起的一瞬间触发的事件。

    因此,对于我们常常做的一些操作,相应的事件触发顺序如下:

    • 点击屏幕后立刻抬起手指:DOWN -> UP
    • 滑动屏幕:DOWN -> MOVE -> ... -> MOVE -> UP

    使用MotionEvent类,我们还可以获取到触摸屏幕时View的一些位置参数:

    • x:当前触摸的位置相对于目标View的X轴坐标,通过getX()方法获取;
    • y:当前触摸的位置相对于目标View的Y轴坐标,通过getY()方法获取;
    • rawX:当前触摸的位置相对于屏幕最左边的X轴坐标,通过getRawX()方法获取;
    • rawY:当前触摸的位置相对于屏幕最上边的Y轴坐标,通过getRawY()方法获取

    TouchSlop指的是 认为是滑动的最小距离。也就是在屏幕上滑动距离大于等于这个数才能算是滑动。

    通过如下方式即可获取这个常量

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

    View事件的工具类VelocityTracker/GestureDetector/Scroller

    VelocityTracker

    VelocityTracker用于追踪手指滑动的速度。具体使用过程如下:

    public class TestVelocityView extends View {
    
        //用于回调的接口
        GetVelocityListener listener;
        //追踪速度关键的类。没有这个这篇文章将毫无意义
        VelocityTracker velocityTracker;
        //要画文字或者任何东西都需要的paint
        Paint paint = new Paint();
    
        public GetVelocityListener getListener() {
            return listener;
        }
    
        public void setListener(GetVelocityListener listener) {
            this.listener = listener;
        }
    
        public TestVelocityView(Context context) {
            this(context,null);
        }
    
        public TestVelocityView(Context context, AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public TestVelocityView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            paint.setTextSize(50);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //画文字的代码。
            canvas.save();
            paint.setColor(Color.BLACK);
            canvas.drawText("x = "+xVelocity+"y ="+yVelocity,getLeft(),getTop(),paint);
          //画完之后回收一下
            canvas.restore();
        }
    
        int xVelocity = 0;
        int yVelocity = 0;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //初始化
                    velocityTracker = VelocityTracker.obtain();
                    break;
                case MotionEvent.ACTION_MOVE:
                  //追踪
                    velocityTracker.addMovement(event);
                    velocityTracker.computeCurrentVelocity(1000);
                    xVelocity = (int) velocityTracker.getXVelocity();
                    yVelocity = (int) velocityTracker.getYVelocity();
    
                    if (listener != null) {
                        listener.get(xVelocity, yVelocity);
                        //强制刷新一下view,否则不会一直掉onDraw。
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    //回收
                    velocityTracker.clear();
                    velocityTracker.recycle();
                    break;
            }
            return true;
        }
    
        public interface GetVelocityListener {
            public void get(int x, int y);
        }
    }
    
    1. 实例化VelocityTracker对象 velocityTracker = VelocityTracker.obtain();
    2. TouchEvent方法中给VelocityTracker对象绑定MotionEvent对象
    3. 使用computeCurrentVelocity设置速度的时间单位(会影响到后面获取的结果)比如设置为100ms v=100/100ms,如果设置为1000ms,得出的结果为v=1000/1000ms。
    4. 获取 横向 纵向 速度xVelocity = (int) velocityTracker.getXVelocity();
      yVelocity = (int) velocityTracker.getYVelocity();

    最后记得回收:

    velocityTracker.clear();
    velocityTracker.recycle();
    

    GestureDetector

    手势检测的工具类,用于检测用户的单击 双击 滑动 长按等事件。

    具体使用如下:
    0.继承GestureDetector.OnGestureListener接口
    于此同时还有6个方法:

    @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
    
        }
    
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
    
        }
    
        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
            
            return false;
        }
    

    1.定义手势检测器实例,使用``GestureDetector.OnGestureListener`实例化对象。

    GestureDetector detector=new GestureDetector(this);
    //解决长按无法移动屏幕问题
     detector.setIsLongpressEnabled(false);
    

    2.View的onTouchEvent中 直接交给

    @Override
        public boolean onTouchEvent(MotionEvent me) {
            //将该Activity上的触碰事件交给GesturDetector处理
            return detector.onTouchEvent(me);
        }
    

    3.除了以上的6个事件,还有一些而外的事件需要单独添加接口OnDoubleTapListener

    detector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
                @Override
                public boolean onSingleTapConfirmed(MotionEvent e) {
                    return false;
                }
    
                @Override
                public boolean onDoubleTap(MotionEvent e) {
                    return false;
                }
    
                @Override
                public boolean onDoubleTapEvent(MotionEvent e) {
                    return false;
                }
            });
    

    1.onSingleTapConfirmed 严格的单击事件
    2.onDoubleTap 双击事件 不和 onSingleTapConfirmed 一起
    3.onDoubleTapEvent 发生了双击事件

    Scroller

    弹性滑动辅助类,能帮助View实现一个带过度的滑动。

    使用如下:

    View的滑动

    使用上节介绍的Scroller即可,当然也可以用其他方式

    普通的滑动()

    1.scrollTo、scrollBy 只能滑动View的内容 生硬

    1. 使用动画位移 但是View动画只能滑动UI,不能真正滑动View。使用属性动画可以,通过动画改变translationX 和translationY
      3.改变View的布局参数 设置LayoutParams的Margin参数即可

    使用Scroller能弹性的滑动过去。

    相关文章

      网友评论

          本文标题:Android系统知识全览---View知识体系(2)---Vi

          本文链接:https://www.haomeiwen.com/subject/jvtqiftx.html