Android手机作为手持设备,界面显示区域并不是很大,为了有便携的效果,只能牺牲手机的显示区域;这就会带来一个问题,可视内容少;为了不影响用户体验,我们必须要在有限的区域做更多的展示,这就对界面的设计有很高的要求了;假如我们是Google的工程师,我们要怎么来设计界面,以此带来好的体验效果呢?
第一种设计:将界面显示区域切割,根据所需要显示的视图,切割为无数块,每一块对应着一部分视图;如下:
这种界面设计简单粗暴,需要多少个视图,就将界面切割成多少个视图模块,以此来放下所有的视图内容;当然,这样设计显而易见会有问题,当视图越来越多的时候,每一个视图的模块所能展示的区域就会越来越小,这样体验效果是肯定不行的;
第二种设计:既然通过切割显示区域以此来展示视图的方案有问题,那么我们就来试试重叠的效果吧;如下:
这种设计很好的解决了视图模块过多时,显示区域不够展示的问题;但是也会存在问题,每一个显示区域和用户的交互顺序混乱了,比如我要和模块为4的视图做交互,结果触发了视图5的交互效果,而脑洞一方案则没有该问题;既然如此,那么我们能不能针对脑洞二的方案来进行优化呢?
答案是:有的!
当多个模块视图重叠时,要协调好与用户的交互就极其重要了,毕竟涉及到用户体验;
当用户的触碰屏幕的显示区域,我们并不知道哪个模块需要和用户进行交互,而我们又不能让用户和其中一个模块的交互失效,那么我们只能去遍历重叠的模块,由内部的视图来决定是否需要相应用户的操作;
这样就可以解决多个模块视图重叠时,哪个模块需要相应用户交互的问题了;
而这正是Android的事件分发机制;
当然上面只是我的脑洞,用于方便理解,如果你有更好的想法,可以和我交流;
那么这种机制是怎么来实现这种效果的呢?请继续往下看;
在深入分析事件分发之前,先来了解一下事件的来源;
当屏幕被触摸,Linux内核会将硬件产生的触摸事件包装为Event存到/dev/input/event[x]目录下。
接着,系统创建的一个InputReaderThread线程loop起来让EventHub调用getEvent()不断的从/dev/input/文件夹下读取输入事件。
然后InputReader则从EventHub中获得事件交给InputDispatcher。
而InputDispatcher又会把事件分发到需要的地方,比如ViewRootImpl的WindowInputEventReceiver中。
这里只是简单了解一下大概的流程,源码过于复杂,这里不做具体的分析;
概括之:当触摸屏幕的时候,硬件会捕捉到用户的触摸动作,告诉系统内核,系统内核将该事件保存下来,然后有一个线程会将这个事件读取出来,交由专门分发的类进行分发;
当屏幕被触摸时,系统底层会将触摸事件(坐标和时间等)封装成MotionEvent事件返回给上层 View;从用户首次触摸屏幕开始,经历手指在屏幕表面的任何移动,直到手指离开屏幕时结束都会产生一系列事件;
MotionEvent的类型:
在分析事件分发机制之前,我们先来看一下事件分发涉及的设计模式;
这个设计模式是事件分发机制的核心,Google工程师是通过这个设计模式来设计事件分发机制的;理解了这个设计模式有助于我们理解事件分发机制;
而这个设计模式就是责任链模式;
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
下面我们通过一段伪代码来解读这个模式:
// 请求 switch (request) { case 0: // 对象一接收请求并处理 break; case 1: // 对象二接收请求并处理 break; case 2: // 对象三接收请求并处理 break; case 3: // 对象四接收请求并处理 break; case 4: // 对象五接收请求并处理 break;这篇关于Android 事件分发之追本溯源的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!