08.Android之View事件问题

目录介绍

  • 8.0.0.1 简述Android的事件分发机制?dispatchTouchEvent方法的做用是什么?说下View和ViewGroup分发事件?
  • 8.0.0.2 onInterceptTouchEvent方法做用是什么?onTouchEvent的方法的做用是什么?
  • 8.0.0.4 滑动冲突有哪些场景?滑动冲突处理原则是什么?滑动冲突解决办法有哪些?分别是如何解决的?
  • 8.0.0.5 onTouch()、onTouchEvent()和onClick()关系是怎样的,哪个先执行?若是设置了onClickListener, 可是onClick()没有调用,可能产生的缘由?
  • 8.0.0.6 View滑动有哪些方法?这些方法分别是如何实现滑动的?分别有什么优缺点?
  • 8.0.0.7 事件的传递规则是什么?View处理事件的优先级?点击事件传递过程遵循以下顺序?事件传递规则要点?
  • 8.0.0.8 Scroller的做用?Scroller的要点有哪些?Scroller的使用步骤?Scroller工做原理?
  • 8.0.0.9 Activity事件分发的过程?Window事件分发?DecorView的事件分发?根View的事件分发?
  • 8.0.1.0 GestureDetector是干什么用的?GestureDetector做用和注意点?有哪些经常使用的监听方法?
  • 8.0.1.2 View的滑动方式?如何让控件滚动到某一位置?scrollTo()和scrollBy()的区别?Scroller是什么?
  • 8.0.1.4 谈一谈View的工做原理,执行流程,MeasureSpec是什么?有什么做用?
  • 8.0.1.6 SurfaceView和View的区别,说一下SurfaceView的工做原理,为什么不会致使页面卡顿?

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深刻知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,固然也在工做之余收集了大量的面试题,长期更新维护而且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
  • 连接地址:https://github.com/yangchong2...
  • 若是以为好,能够star一下,谢谢!固然也欢迎提出建议,万事起于忽微,量变引发质变!

8.0.0.1 简述Android的事件分发机制?dispatchTouchEvent方法的做用是什么?说下View和ViewGroup分发事件?

  • 简述Android的事件分发机制?技术博客大总结php

    • 事件分发顺序:Activty->ViewGroup->View
    • 主要方法:dispatchTouchEvent-分发事件、onInterceptTouchEvent-当前View是否拦截该事件、onTouchEvent-处理事件
    • 1.父View调用dispatchTouchEvent开启事件分发。
    • 2.父View调用onInterceptTouchEvent判断是否拦截该事件,一旦拦截后该事件的后续事件(如DOWN以后的MOVE和UP)都直接拦截,不会再进行判断。
    • 3.若是父View进行拦截,父View调用onTouchEvent进行处理。
    • 4.若是父View不进行拦截,会调用子View的dispatchTouchEvent进行事件的层层分发。
  • dispatchTouchEvent方法的做用是什么?git

    • 用于进行事件的分发
    • 只要事件传给当前View,该方法必定会被调用
    • 返回结果受到当前View的onTouchEvent和下级View的dispatchTouchEvent影响
    • 表示是否消耗当前事件
  • ViewGroup事件分发伪代码github

    • image
  • View事件分发伪代码面试

    • image
  • View和ViewGroup在dispatchTouchEvent上的区别segmentfault

    • ViewGroup在dispatchTouchEvent()中会进行事件的分发。
    • View在dispatchTouchEvent()中会对该事件进行处理。技术博客大总结

8.0.0.2 onInterceptTouchEvent方法做用是什么?onTouchEvent的方法的做用是什么?

  • onInterceptTouchEvent方法做用是什么?markdown

    • 在dispatchTouchEvent的内部调用,用于判断是否拦截某个事件
    • View和ViewGroup在onInterceptTouchEvent上的区别:布局

      • View没有该方法,View会处理全部收到的事件,但不必定会消耗该事件。
      • onInterceptTouchEvent是ViewGroup中添加的方法,用于判断是否拦截该事件。
  • onTouchEvent的方法的做用是什么?技术博客大总结post

    • 在dispatchTouchEvent的中调用,用于处理点击事件
    • 返回结果表示是否消耗当前事件

8.0.0.4 滑动冲突有哪些场景?滑动冲突处理原则是什么?滑动冲突解决办法有哪些?分别是如何解决的?

  • 滑动冲突有哪些场景?学习

    • 内层和外层滑动方向不一致:一个垂直,一个水平。好比轮播图ViewPager和ScrollView
    • 内存和外层滑动方向一致:均垂直or水平。好比scrollView和RecyclerView
    • 前二者层层嵌套。好比ScrollView和RecyclerView(recyclerView中又嵌套recyclerView)
  • 滑动冲突处理原则动画

    • 对于内外层滑动方向不一样,只须要根据滑动方向来给相应控件拦截
    • 对于内外层滑动方向相同,须要根据业务来进行事件拦截,规定什么时候让外部View拦截事件什么时候由内部View拦截事件。
    • 前二者嵌套的状况,根据前两种原则层层处理便可。
  • 滑动冲突解决办法有哪些?技术博客大总结

    • 外部拦截法:指点击事件都先通过父容器的拦截处理,若是父容器须要此事件就拦截,不然就不拦截。具体方法:须要重写父容器的onInterceptTouchEvent方法,在内部作出相应的拦截。
    • 内部拦截法:指父容器不拦截任何事件,而将全部的事件都传递给子容器,若是子容器须要此事件就直接消耗,不然就交由父容器进行处理。具体方法:须要配合requestDisallowInterceptTouchEvent方法。
  • 外部拦截解决滑动冲突法

    • 外部拦截法要点

      • 父容器的onInterceptTouchEvent方法中处理
      • ACTION_DOWN不拦截,一旦拦截会致使后续事件都直接交给父容器处理。
      • ACTION_MOVE中根据状况进行拦截,拦截:return true,不拦截:return false(外部拦截核心)
      • ACTION_UP不拦截,若是父控件拦截UP,会致使子元素接收不到UP进一步会让onClick方法没法触发。此外UP拦截也没什么用。
    • onClick方法生效的两个条件?

      • View能够点击
      • 接收到了DOWN和UP事件
    • 外部拦截,自定义ScrollView,这块能够看个人博客:

8.0.0.5 onTouch()、onTouchEvent()和onClick()关系是怎样的,哪个先执行?若是设置了onClickListener, 可是onClick()没有调用,可能产生的缘由?

  • onTouch()、onTouchEvent()和onClick()关系是怎样的,哪个先执行?

    • onTouch->onTouchEvent->onClick

      • 当一个View须要处理事件时,若是它设置了OnTouchListener,那么OnTouchListener的onTouch方法会被回调。
      • 这时事件如何处理还得看onTouch的返回值,若是返回false,则当前View的onTouchEvent方法会被调用;若是返回true,那么onTouchEvent方法将不会被调用。因而可知,给View设置的onTouchListener,其优先级比onTouchEvent要高。
      • 若是当前方法中设置了onClickListener,那么它的onClick方法会被调用。能够看出,经常使用的OnClickListener,其优先级别最低。
  • 若是设置了onClickListener, 可是onClick()没有调用,可能产生的缘由? 技术博客大总结

    • 父View拦截了事件,没有传递到当前View
    • View的Enabled = false(setEnabled(false)): view处于不可用状态,会直接返回。
    • View的Clickable = false(setClickablesetLongClickable(false)):view不能够点击,不会执行onClick
    • View设置了onTouchListener,且消耗了事件。会提早返回。
    • View设置了TouchDelegate,且消耗了事件。会提早返回。

8.0.0.6 View滑动有哪些方法?这些方法分别是如何实现滑动的?分别有什么优缺点?

  • View滑动有哪些方法?

    • layout:对View进行从新布局定位。在onTouchEvent()方法中得到控件滑动先后的偏移。而后经过layout方法从新设置。
    • offsetLeftAndRight和offsetTopAndBottom:系统提供上下/左右同时偏移的API。onTouchEvent()中调用
    • LayoutParams: 更改自身布局参数
    • scrollTo/scrollBy: 本质是移动View的内容,须要经过父容器的该方法来滑动当前View
    • Scroller: 平滑滑动,经过重载computeScroll(),使用scrollTo/scrollBy完成滑动效果。
    • 属性动画: 动画对View进行滑动技术博客大总结
    • ViewDragHelper: 谷歌提供的辅助类,用于完成各类拖拽效果。
  • Layout实现滑动

    • image
  • offsetLeftAndRight和offsetTopAndBottom实现滑动

    • image
  • LayoutParams实现滑动

    • 经过父控件设置View在父控件的位置,但须要指定父布局的类型,很差
    • 用ViewGroup的MariginLayoutParams的方法去设置margin

      //方法一:经过布局设置在父控件的位置。可是必需要有父控件, 并且要指定父布局的类型,很差的方法。 
      RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams(); 
      layoutParams.leftMargin = getLeft() + offsetX; 
      layoutParams.topMargin = getTop() + offsetY; 
      setLayoutParams(layoutParams);
      /**===============================================
       * 方法二:用ViewGroup的MarginLayoutParams的方法去设置marign
       * 优势:相比于上面方法, 就不须要知道父布局的类型。
*===============================================*/ 
    ViewGroup.MarginLayoutParams mlayoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
    mlayoutParams.leftMargin = getLeft() + offsetX; 
    mlayoutParams.topMargin = getTop() + offsetY; 
    setLayoutParams(mlayoutParams);
    ```
  • scrollToscrollBy实现滑动

    • 都是View提供的方法。
    • scrollTo-直接到新的x,y坐标处。
    • scrollBy-基于当前位置的相对滑动。
    • scrollBy-内部是调用scrollTo.
    • scrollToscrollBy, 效果是移动View的内容,所以须要在View的父控件中调用。
    • scrollTo/By内部的mScrollX和mScrollY的意义

      • mScrollX的值,至关于手机屏幕相对于View左边缘向右移动的距离,手机屏幕向右移动时,mScrollX的值为正;手机屏幕向左移动(等价于View向右移动),mScrollX的值为负。
      • mScrollY和X的状况类似,手机屏幕向下移动,mScrollY为+正值;手机屏幕向上移动,mScrollY为-负值。
      • mScrollX/Y是根据第一次滑动前的位置来得到的,例如:第一次向左滑动200(等于手机屏幕向右滑动200),mScrollX = 200;第二次向右滑动50, mScrollX = 200 + (-50)= 150,而不是(-50)。
  • 动画实现滑动的方法

    • 能够经过传统动画或者属性动画的方式实现
    • 传统动画须要经过设置fillAfter为true来保留动画后的状态(可是没法在动画后的位置进行点击操做,这方面仍是属性动画好)
    • 属性动画会保留动画后的状态,可以点击。技术博客大总结
  • ViewDragHelper

    • 经过ViewDragHelper去自定义ViewGroup让其子View具备滑动效果。不过用的不多

8.0.0.7 事件的传递规则是什么?View处理事件的优先级?点击事件传递过程遵循以下顺序?事件传递规则要点?

  • 事件的传递规则是什么?

    • 点击事件产生后,会先传递给根ViewGroup,并调用dispatchTouchEvent
    • 以后会经过onInterceptTouchEvent判断是否拦截该事件,若是true,则表示拦截并交给该ViewGroup的onTouchEvent方法进行处理
    • 若是不拦截,则当前事件会传递给子元素,调用子元素的dispatchTouchEvent,如此反复直到事件被处理
  • View处理事件的优先级?

    • 在View须要处理事件时,会先调用OnTouchListener的onTouch方法,并判断onTouch的返回值
    • 返回true,表示处理完成,不会调用onTouchEvent方法
    • 返回false,表示未完成,调用onTouchEvent方法进行处理
    • 可见,onTouchEvent的优先级没有OnTouchListener高
    • onTouchEvent没有消耗的话就会交给TouchDelegate的onTouchEvent去处理。
    • 若是最后事件都没有消耗,会在onTouchEvent中执行performClick()方法,内部会执行OnClickListener的onClick方法,优先级最低,属于事件传递尾端
  • 点击事件传递过程遵循以下顺序?技术博客大总结

    • Activity->Window->View->分发
    • 若是View的onTouchEvent返回false,则父容器的onTouchEvent会被调用,最终能够传递到Activity的onTouchEvent
  • 事件传递规则要点?

    • View一旦拦截事件,则整个事件序列都由它处理(ACTION_DOWNUP等),onInterceptTouchEvent不会再调用(由于默认都拦截了)
    • 可是一个事件序列也能够经过特殊方法交给其余View处理(onTouchEvent)
    • 若是View开始处理事件(已经拦截),若是不消耗ACTIO_DOWN事件(onTouchEvent返回false),则同一事件序列的剩余内容都直接交给父onTouchEvent处理
    • View消耗了ACTION_DOWN,但不处理其余的事件,整个事件序列会消失(父onTouchEvent)不会调用。这些消失的点击事件最终会传给Activity处理。
    • ViewGroup默认不拦截任何事件(onInterceptTouchEvent默认返回false)
    • View没有onInterceptTouchEvent方法,一旦有事件传递给View,onTouchEvent就会被调用
    • View的onTouchEvent默认都会消耗事件return true, 除非该View不可点击(clickable和longClickable同时为false)
    • View的enable属性不影响onTouchEvent的默认返回值。即便是disable状态。
    • onClick的发生前提是当前View可点击,而且收到了down和up事件
    • 事件传递过程是由父到子,层层分发,能够经过requestDisallowInterceptTouchEvent让子元素干预父元素的事件分发(ACTION_DOWN除外)

8.0.0.8 Scroller的做用?Scroller的要点有哪些?Scroller的使用步骤?Scroller工做原理?

  • Scroller的做用?

    • 用于封装滑动
    • 提供了基于时间的滑动偏移值,可是实际滑动须要咱们去负责。
  • Scroller的要点有哪些?

    • 调用startScroll方法时,Scroller只是单纯的保存参数
    • 以后的invalidate方法致使的View重绘
    • View重绘以后draw方法会调用本身实现的computeScroll(),才真正实现了滑动
  • Scroller的使用步骤?

    • image
  • Scroller工做原理?技术博客大总结

    • Scroller自己不能实现View的滑动,须要配合View的computeScroll方法实现弹性滑动
    • 不断让View重绘,每一次重绘距离滑动的开始时间有一个时间间隔,经过该时间能够获得View当前的滑动距离
    • View的每次重绘都会致使View的小幅滑动,屡次小幅滑动就组成了弹性滑动

8.0.0.9 Activity事件分发的过程?Window事件分发?DecorView的事件分发?根View的事件分发?

  • Activity事件分发的过程?

    • 事件分发过程:Activity->Window->Decor View(当前界面的底层容器,setContentView的View的父容器)->ViewGroup->View
    • Activity的dispatchTouchEvent,会交给Window处理(getWindow().superDispatchTouchEvent()),
    • 返回true:事件所有结束
    • 返回false:全部View都没有处理(onTouchEvent返回false),则调用Activity的onTouchEvent
  • Window事件分发?

    • Window和superDispatchTouchEvent分别是抽象类和抽象方法
    • Window的实现类是PhoneWindow
    • PhoneWindow的superDispatchTouchEvent()直接调用mDecor.superDispatchTouchEvent(),也就是直接传给了DecorView
  • DecorView的事件分发?

    • DecorView继承自FrameLayout
    • DecorView的superDispatchTouchEvent()会调用super.dispatchTouchEvent()——也就是ViewGroup的dispatchTouchEvent方法,以后就会层层分发下去。
  • 根View的事件分发?技术博客大总结

    • 顶层View调用dispatchTouchEvent
    • 调用onInterceptTouchEvent方法
    • 返回true,事件由当前View处理。若是有onTouchiListener,会执行onTouch,而且屏蔽掉onTouchEvent。没有则执行onTouchEvent。若是设置了onClickListener,会在onTouchEvent后执行onClickListener
    • 返回false,不拦截,交给子View重复如上步骤。

8.0.1.0 GestureDetector是干什么用的?GestureDetector做用和注意点?有哪些经常使用的监听方法?

  • GestureDetector做用和注意点?

    • 探测手势和事件,须要经过提供的MotionEvent
    • 该类仅能用于touch触摸提供的MotionEvent,不能用于traceball events(追踪球事件)
    • 能够在自定义View中重写onTouchEvent()方法并在里面用GestureDetector接管。
    • 能够在View的setOnTouchListener的onTouch中将点击事件交给GestureDetector接管。
  • 有哪些经常使用的监听方法?

    • OnGestureListener
    • OnDoubleTapListener
    • OnContextClickListener
    • SimpleOnGestureListener
  • OnGestureListener

    • OnGestureListener做用技术博客大总结

      • 用于在手势产生时,去通知监听者。
      • 该监听器会监听全部的手势,若是只须要监听一部分可使用SimpleOnGestureListener
    • OnGestureListener能监听哪些手势

      • 按下操做。
      • 按下以后,Move和Up以前。用于提供视觉反馈告诉用户已经捕获了他们的行为。
      • 抬起操做。
      • 滑动操做(由Down MotionEvent e1触发,当前是Move MotionEvent e2)
      • 长按操做。
      • 猛扔操做。
      • 全部有返回值的回调方法,return true-消耗该事件;return false-不消耗该事件
  • OnDoubleTapListener

    • OnDoubleTapListener做用

      • 监听“双击操做”
      • 监听“确认的单击操做”—该单击操做以后的操做没法构成一次双击。
    • OnDoubleTapListener能监听哪些手势?

      • 单击操做。
      • 双击操做.
      • 双击操做之间发生了down、move或者up事件。

8.0.1.2 View的滑动方式?如何让控件滚动到某一位置?scrollTo()和scrollBy()的区别?Scroller是什么?

  • View的滑动方式?

    • 三种方式:

      • a. 经过View自己提供的scrollTo/scrollBy方法

        • 移动的是View的内容,View自己不移动
      • b. 经过动画给View施加平移效果实现滑动

        • 经过补间动画移动的View的影像,View自己位置不发生改变。经过属性动画移动view的影像,view自己位置会发生改变。
      • c. 经过改变View的LayoutParams使View从新布局实现滑动

        • 改变布局参数,代码以下:
        MarginLayoutParams params = (MarginLayoutParams) mButton.getLayoutParams();
        params.width += 10;
        params.height += 10;
        mButton.setLayoutParams(params);
    • 三种方法的使用对比

      • scrollTo/scrollBy:操做简单,适合对View内容的滑动;
      • 动画:操做简单,主要适合于没有交互的View和实现复杂的动画效果;
      • 改变布局参数:操做稍微复杂,适用于有交互的View。
  • scrollTo()和scrollBy()技术博客大总结

    • scrollBy内部调用了scrollTo,它是基于当前位置的相对滑动;而scrollTo是绝对滑动,所以若是利用相同输入参数屡次调用scrollTo()方法,因为View初始位置是不变只会出现一次View滚动的效果而不是屡次。
    • 引伸:二者都只能对view内容进行滑动,而不能使view自己滑动,且非平滑,可以使用Scroller有过渡滑动的效果。
  • Scroller实现滑动的具体过程:

    • 在MotionEvent.ACTION_UP事件触发时调用startScroll()方法,该方法并无进行实际的滑动操做,而是记录滑动相关量
    • 立刻调用invalidate/postInvalidate()方法,请求View重绘,致使View.draw方法被执行
    • 紧接着会调用View.computeScroll()方法,此方法是空实现,须要本身处理逻辑。具体逻辑是:先判断computeScrollOffset(),若为true(表示滚动未结束),则执行scrollTo()方法,它会再次调用postInvalidate(),如此反复执行,直到返回值为false。
    • image

8.0.1.4 谈一谈View的工做原理,执行流程,MeasureSpec是什么?有什么做用?

  • View工做流程

    • View工做流程简单来讲就是,先measure测量,用于肯定View的测量宽高,再 layout布局,用于肯定View的最终宽高和四个顶点的位置,最后 draw绘制,用于将View 绘制到屏幕上。
    • image
    • ViewRoot对应于ViewRootImpl类,它是链接WindowManager和DecorView的纽带。
    • View的绘制流程是从ViewRoot和performTraversals开始。
    • performTraversals()依次调用performMeasure()、performLayout()和performDraw()三个方法,分别完成顶级 View的绘制。
    • 其中,performMeasure()会调用measure(),measure()中又调用onMeasure(),实现对其全部子元素的measure过程,这样就完成了一次measure过程;接着子元素会重复父容器的measure过程,如此反复至完成整个View树的遍历。layout和draw同理。
  • MeasureSpec做用技术博客大总结

    • 经过宽测量值widthMeasureSpec和高测量值heightMeasureSpec决定View的大小

      • MeasureSpec组成:一个32位int值,高2位表明SpecMode(测量模式),低30位表明SpecSize
      • 直接继承View的自定义View须要重写onMeasure()并设置wrap_content时的自身大小,不然效果至关于macth_parent
    • SpecMode有三类:

      • UNSPECIFIED 表示父容器不对View有任何限制,通常用于系统内部,表示一种测量状态;
      • EXACTLY 父容器已经检测出view所需的精确大小,这时候view的最终大小SpecSize所指定的值,至关于match_parent或指定具体数值。
      • AT_MOST 父容器指定一个可用大小即SpecSize,view的大小不能大于这个值,具体多大要看view的具体实现,至关于wrap_content。

8.0.1.6 SurfaceView和View的区别,说一下SurfaceView的工做原理,为什么不会致使页面卡顿?

  • SurfaceView是从View基类中派生出来的显示类,他和View的区别有:

    • View须要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
    • View适用于主动更新的状况,而SurfaceView适用于被动更新,如频繁刷新,这是由于若是使用View频繁刷新会阻塞主线程,致使界面卡顿技术博客大总结
    • SurfaceView在底层已实现双缓冲机制,而View没有,所以SurfaceView更适用于须要频繁刷新、刷新时数据处理量很大的页面

关于其余内容介绍

01.关于博客汇总连接

02.关于个人博客

相关文章
相关标签/搜索