自定义View学习笔记2

绘制View的相关知识点:让绘图更加炫酷的Paint、让View动起来的动画、与用户交互的触控事件

一:事件分发机制原理(责任链模式,事件层层传递,直到被消费)

      事件分为:分发、拦截、消费

      

        如果分发下的事件没有任何View消费,那么会反向回传,最终传给Activity,最终Activity也没有处理,本事件才会被抛弃

        回传都是直接在询问onTouch是否执行,false回传上去

        注意:

        1. 事件被消费 -- 事件信息停止传递

        2. 事件一直没有被消费,最后传给activity,activity不需要则抛弃

        3. 判断事件是否被消费是根据返回值,而不是根据你是否使用了事件 

二:事件分发机制详解

       1. 常见事件(事件被封装在MotionEvent对象中):

            ACTION_DOWN:手指初次接触屏幕时触发

            ACTION_MOVE:手指在屏幕上滑动时触发(会多次触发)

            ACTION_UP:手指离开屏幕时触发

            ACTION_CANCEL:事件被上层拦截时触发

       2. 相关方法:

            dispatchTouchEvent:事件分发机制中的核心(View存在分发机制,是用来管理单击、长按、触摸灯相关事件)

                  View调用顺序:

                          onTouchListener - onTouchEvent - onLongClickListener - onClickListener

                          返回ture,事件被消费,false不消费,与是否使用了事件无关

                          不论View是否注册点击事件,只要View是可点击的就会消费事件

                 ViewGroup的分发流程:

                          判断自身是否需要(询问onInterceptTouchEvent是否拦截),需要调用onTouchEvent

                          不需要/不确定:询问childView(手机当前触摸的点所在的view)

                          childView不需要则调用自身的onTouchEvent

            注意:为了保证所有事件被同一个View消费,View只有消费了ACTION_DOWN事件,才能接收到后续事件(除非被上层View拦截,此时会收到ACTION_CANCEL,表示当前事件已结束,后续事件不会再传递)

          要点:

                     1. 分发原理:责任链模式,事件层层传递,直到被消费

                     2. View的dispatchTouchEvent主要用于调度自身的监听器和onTouchEvent

                     3. View事件调度顺序:onTouchListener - onTouchEvent - oLongClickListener - onClickListener

                     4. 不论View是否注册点击事件,只要是可点击的就会消费事件

                     5. 事件是否被消费由返回值决定,true 表示消费,false 表示不消费,与是否使用了事件无关。

                     6. ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView。

                     7. ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费。

                     8. 一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。

                     9. 只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后续内容。

                     10. 如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来

三:MotionEvent

     1. 单点触控

         事件:初次接触屏幕 - ACTION_DOWN

                    在屏幕上滑动(执行多次) - ACTION_MOVE

                    离开屏幕 - ACTION_UP

                    被上层拦截 - ACTION_CANCEL

                    不在控件区域 - ACTION_OUTSIDE

        方法: 获取事件类型 - getAction()

                    获取触摸点在当前View的X坐标 - getX()

                    获取触摸点在当前View的Y坐标 - getY()

                    获取触摸点在整个屏幕的X坐标 - getRawX()

                    获取触摸点在整个屏幕的Y坐标 - getRawY()

       ACTION_CANCEL:正常被上层V皆为拦截后,当前View是收不到任何事件的

                                         触发条件:上层View回收事件处理权的时候,当前View会收到Cancel事件

           例:listView滚动事件,item收到down事件,但是listView收到滚动事件,所以收回事件处理权,此时item会收到cancel

      ACTION_OUTSIDE:设置视图WindowManager布局参数的flag为FLAG_WATCH_OUTSIDE_TOUCH,如此会接收到该事件

   2. 多点触控

       

       

  注意:

   * 多点触控必须使用getActionMasked获取事件类型

   * 点击触控,由于事件数值不变所以,使用getAction和getActionMasked都可以

   * 使用getActionIndex可以获取到index数值,不过只有在down和up时有效,move无效

   * pointId是唯一不变的标识,在按下时产生,在抬起或 取消时消失

  获取事件类型:

  取得事件索引:

 **  index和pointId变化规则:

  index --- * 从0开始自动增长

                * 如果之前落下的手指抬起,后面手指的index会随之减小

                * 对move事件无效

   pointId --- pointId是不变的,始终为第一次落下时生成的数值,不会收其他手指抬起和落下的影响

   

  **  move相关事件

       pointerIndex和pointId  

 

3. 历史数据处理:

     

  注意:

    * pin是指pointerIndex,表示第几根手指

    * 历史数据只有ACTION_MOVE

    * 历史数据单点触控和多点触控均可以用

4. 获取事件发生的时间

    

     * pos表示历史数据中第几个数据

     * 返回值类型为long,单位是毫秒

 5. 获取压力(接触面积大小)

      

      * 获取接触面积大小和获取压力大小时需要硬件支持的

      * 大多数电容屏不支持压力测试,但可以大致测试出接触面积

      * 大部分设备的getPressure是使用接触面积来模拟的

      * 有些设备不支持该方法(系统版本和硬件问题导致的)

  6. 鼠标事件

      

      * 4.0以上才添加的

      * 使用geyActionMasked获取事件类型

      * 事件不会传递到onTouchEvent,而是会传递到onGenericMotionEvent

  7. 输入设备类型判断

     

      使用getToolType(int pointerIndex)获取对应输入类型,可以为0,但必须小于getPointCount

 四:特殊控件事件处理方法

        1. Region区域检测(是一个封闭区域,可以通过contains判断是否在该区域)

         2. Matrix的坐标映射   

五:手势检测GestureDetector

        1. 使用:  

        2. 构造函数:

             handler为了给GestureDetector提供一个looper(如果是在主线程中,不存在该问题,因为它内部自动创建handler用于处理数据; 如果是在没有创建looper的子线程中,则需要传递handler,否则无法获取到looper导致创建失败)

        3. 手势监听器

             3.1 OnContextClickListener:用于检测外部设备按钮

                   注意:如果侦听 onContextClick(MotionEvent),则必须在 View 的 onGenericMotionEvent(MotionEvent)中调用 GestureDetector 的 OnGenericMotionEvent(MotionEvent)

             3.2 OnDoubleTapListener:检测双击

                   回调接口:onDoubleTap  -  只是监听双击事件

                                      onSingleTapConfirmed  - 同时监听单击事件(发生300ms后才触发)

                     因为单击事件不是立即发生,所以在执行点击操作后单击监听和双击监听只会有一个被触发,不会出现冲突

                                       onDoubleTapEvent - 双击事件发生时会对第二次按下产生的MationEvent信息进行回调

                     如果需要细微的控制双击事件,使用onDoubleTagEvent更好

            3.3 OnGestureListener(检测以下事件类型)

                      按下Down(View能够接收到事件: view设置为可点击,因为可点击状态会默认消费down事件、手动消费down事件)               onFling(手指抬起后还会滚动一段时间才会停止,参数:e1 - 按下event、e2 - 抬起event、velocityX - X上运动速度像素/秒、velocityY - Y轴上运动速度像素/秒)

                   onLongPress(检测长按事件)

                   onScroll监听滚动事件(后俩个参数distanceX和distanceY是指滚动距离)

                   onShowPress按下时的一种回调(作用:给用户提供视觉反馈),延时180ms回调

                   onSingTagUp用户单击提起时回调(双击第一次抬起时触发)

              3.4 SimpleOnGestureListener:对以上三种监听的空实现(OnGestureListener 创建会出现无用的空实现,所以一般是会用改监听)

        4. 相关方法

             

六:缩放手势检测ScaleGestureDetector

        1. 构造方法和GestureDetector 类似

         2. 手势监听器

              方法:

        3. 原理:计算缩放中心点 - 所有坐标加起来/数量

                       计算缩放比例 - 各个手指到焦点的平均距离(新的平均距离 - 旧的平均距离)

             移动距离超过一定书之后,会触发onScaleBegin方法,如果在onScaleBegin方法里范湖里true,表示接收事件后,就会重置缩放相关数值,并且开始积累缩放因子

七:画笔基础

      1. 基础

           内部类:Paint.Cap - 描边线和路径的开始和结束显示效果三种效果叠加(butt中间线区域,round圆形线区域,square红色和绿色组成部分边是直角)

                         Paint.Join - 线条和曲线段在描边路径上连接处理

                          Paint.Style - 绘制的图元是否被填充,描边或者俩者均有

           常量:ANIT_ALIAS_FLAG - 开启矿锯齿功能

                      DITHER_FLAG - 绘制时启用抖动的标志

                      FILTER_BITMAP_FLAG - 绘制标志,在缩放的位图上启用双线性采样

           构造方法:Paint() - 默认设置创建一个新画笔

                             Paint(int flag) - 创建新画笔并提供特殊设置通过flag参数

                             Paint(Paint paint) - 使用指定画笔参数初始化新画笔

           公开方法:获取和设置画笔相关的一些设置:getFlags/setFlags(会覆盖之前设置的内容)

                             复制画笔设置和回复默认设置:set(Paint src)/reset()

                             获取和设置alpha值:getAlpha()/setAlpha(int a)

                             获取和设置画笔颜色:getColor()/setColor(int color)

                             设置带透明通道颜色:setARGB(int a,int r,int g,int b)

                             获取和设置描边宽度:getStrokeWidth()/setStrokeWidth(float width)

                             获取(控制如何处理描边线和路径的开始和结束)和设置cap:getStrokeCap()/setStrokeCap(Paint.Cap cap)

                             获取和设置画笔连接方式:getStrokeMiter()/setStrokeMiter(float miter)

                             获取和设置画笔的patheffect:getPathEffect()/setPathEffect(PathEffect effect)

                             将不同效果应用于src,并将结果返回到dst:getFillPath(Path src,Path dst)

      2. 画笔设置

           创建方式: 

           画笔颜色:

                             

           画笔宽度:(宽度向俩边延伸,值为0,画布如何放大值不变,值为1,会随画布而增大)

           画笔模式:

           画笔线帽:包含以下三种:

           

             注意:

           线段连接方式(拐角类型):包含三种方式

                 

           衔接模式长度限制

              线段连接方式默认是 MITER,即在拐角处延长外边缘,直到相交位置

            

           为了避免这种情况,如果连接模式为 MITER(尖角),当连接角度小于一定程度时会自动将连接模式转换为 BEVEL(平角)

           mater是对长度的限制,它可以通过这个公司计算:miter = 1/sin(angle/2),angle是俩条线夹角,miter默认是4,必须大于0才有效

      3. CornerPathEffect:可以将线段之间的任何锐角替换为指定半径的圆角(适用于STROKE或FILL样式,半径越大越平滑)

      4. 实现虚线效果DashPathEffect(适用于STROKE或FILL_AND_STROKE)

          参数:float intervals[] - 显示长度和隐藏长度

                     float phase - 相位 

          注意:intervals[] 中是允许设置多组数据的,每两个为一组,第一个表示显示长度,第二个表示隐藏长度

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值