前面说过UIViewController,但是UIView也是在MVC中非常重要的一层。正是因为UIView是Iphone下所有界面的基础,所以官方专门写了一个文档“ViewProgrammingGuideforiOS”。通过这个可以很好的了解UIView的功能。
先来看看官方API的解释:TheUIViewclassdefinesarectangularareaonthescreen
andtheinterfacesformanagingthecontentinthatarea.
Atruntime,aviewobjecthandlestherenderingofanycontentinitsarea
andalsohandlesanyinteractionswiththatcontent.(UIView在屏幕上定义了一个矩形区域和管理区域内容的接口。在运行时,一个视图对象控制该区域的渲染,同时也控制内容的交互。)。所以说UIView具有三个基本的功能,画图和动画,管理内容的布局,控制事件。正是因为UIView具有这些功能,它才能担当起MVC中视图层的作用。
UIView咋看起来很复杂,官方API中各种函数接口,要学过运用庖丁解牛的思想,逐个分析,因为再复杂的东西都是有简单的东西构成的。回到刚才提到的UIView的三个基本功能就可以容易的分离出UIView不同的功能是怎么组合起来的。首先看视图最基本的功能显示和动画,其实UIView的所有的绘图和动画的接口,都是可以用CALayer和CAAnimation实现的,也就是说苹果公司是不是把CoreAnimation的功能封装到了UIView中,这个文档中没有提到过,也没法断言。但是每一个UIView都会包含一个CALayer,并且CALayer里面可以加入各种动画。再次我们来看UIView管理布局的思想其实和CALayer也是非常的接近的。最后控制事件的功能,是因为UIView继承了UIResponder。经过上面的分析很容易就可以分解出UIView的本质。UIView就相当于一块白墙,这块白墙只是负责把加入到里面的东西显示出来而已。
图1
1.UIView中的CALayer
UIView的一些几何特性frame,bounds,center都可以在CALayer中找到替代的属性,所以如果明白了CALayer的特点,自然UIView的图层中如何显示的都会一目了然。
CALayer就是图层,图层的功能自然就有渲染图片,播放动画的功能。每当创建一个UIView的时候,系统会自动的创建一个CALayer,但是这个CALayer对象你不能改变,只能修改某些属性。所以通过修改CALayer,不仅可以修饰UIView的外观,还可以给UIView添加各种动画。CALayer属于CoreAnimation框架中的类,通过CoreAnimationProgrammingGuide就可以了解很多CALayer中的特点,假如掌握了这些特点,自然也就理解了UIView是如何显示和渲染的。
先来看下CoreAnimation框架中关于layer的解释:WhilethereareobvioussimilaritiesbetweenCoreAnimationlayersandCocoaviewsthebiggest
conceptualdivergenceisthatlayersdonotrenderdirectlytothescreen.
WhereNSViewandUIViewareclearlyviewobjectsinthemodel-view-controllerdesignpattern,
CoreAnimationlayersareactuallymodelobjects.Theyencapsulategeometry,timingandvisualproperties,
andtheyprovidethecontentthatisdisplayed,
buttheactualdisplayisnotthelayer’sresponsibility.
Eachvisiblelayertreeisbackedbytwocorrespondingtrees:apresentationtreeandarendtree(非常相似的cocoa视图和coreAnimation层最大的区别是coreAnimation不能直接渲染到屏幕上。UIView和NSView明显是MVC中的视图模型,animationlayer更像是模型对象。他们封装了几何,时间和一些可视的属性,并且提供了可以显示的内容,但是实际的显示并不是layer的职责。每一个层树的后台都有两个响应树:一个曾现树和一个渲染树)。所以很显然Layer封装了模型数据,每当更改layer中的某些模型数据中数据的属性时,曾现树都会做一个动画代替,之后由渲染树负责渲染图片。
既然AnimationLayer封装了对象模型中的几何性质,那么如何取得这些几何特性。一个方式是根据Layer中定义的属性,比如bounds,authorPoint,frame等等这些属性,其次,CoreAnimation扩展了键值对协议,这样就允许开发者通过get和set方法,方便的得到layer中的各种几何属性。下表是Transform的keypaths。例如转换动画的各种几何特性,大都可以通过此方法设定:
图2
虽然CALayer跟UIView十分相似,也可以通过分析CALayer的特点理解UIView的特性,但是毕竟苹果公司不是用CALayer来代替UIView的,否则苹果公司也不回设计一个UIView类了。就像官方文档解释的一样,CAlayer层树是cocoa视图继承树的同等物,它具备UIView的很多共同点,但是CoreAnimation没有提供一个方法展示在窗口。他们必须宿主到UIView中,并且UIView给他们提供响应的方法。所以UIReponder就是UIView的又一个大的特性。
2.UIView继承的UIResponder
UIResponder是所有事件响应的基石,官方也提供了一个重要的文档给开发者参考”EventHandlingGuideforiOS”。
事件(UIEvent)是发给应用程序,告知用户的行动的。在IOS中事件有三种事件:多点触摸事件,行动事件,远程控制事件。三种事件定义如下:
再来看下UIReponder中的事件传递过程,如下图所示:
图3
首先是被点击的该视图响应时间处理函数,如果没有响应函数就逐级的向上面传递,直到有响应处理函数,或者该消息被抛弃。至于苹果公司是如何让事件消息这样流动的,在下面的分析中,可以了解一些,至于深层的原理还的进一步挖掘。
这里重点看三个事件中的多点触摸事件,也就是UITouch事件,下图是UIEvent中封装的UITouch内容
图4
关于UIView的触摸响应事件中,这里有一个常常容易迷惑的方法hitTest:WithEvent。先来看官方的解释:ThismethodtraversestheviewhierarchybysendingthepointInside:withEvent:message
toeachsubviewtodetermine whichsubviewshouldreceiveatouchevent.
IfpointInside:withEvent:returnsYES,thenthesubview’shierarchyistraversed;
otherwise,itsbranchoftheviewhierarchyisignored.
Yourarelyneedtocallthismethodyourself,
butyoumightoverrideittohidetoucheventsfromsubviews.(通过发送PointInside:withEvent:消息给每一个子视图,这个方法遍历视图层树,来决定那个视图应该响应此事件。如果PointInside:withEvent:返回YES,然后子视图的继承树就会被遍历;否则,视图的继承树就会被忽略。你很少需要调用这个方法,仅仅需要重载这个方法去隐藏子视图的事件)。从官方的API上的解释,可以看出hitTest方法中,要先调用PointInside:withEvent:,看是否要遍历子视图。如果我们不想让某个视图响应事件,只需要重载PointInside:withEvent:方法,让此方法返回NO就行了。不过从这里,还是不能了解到hitTest:WithEvent的方法的用途。
下面再从”EventHandlingGuideforiOS”找答案,Yourcustomrespondercanusehit-testingtofindthesubvieworsublayerofitselfthatis"under”atouch,andthenhandletheeventappropriately。从中可以看出hitTest主要用途是用来寻找那个视图是被触摸了。看到这里对hitTest的调用过程还是一知半解。我们可以实际建立一个工程进行调试。建立一个MyView里面重载hitTest和pointInside方法:
然后在MyView中增加一个子视图MySecondView也重载这两个方法
这里注意[superhitTest:pointwithEvent:event];必须要包括,否则hitTest无法调用父类的方法,这样就没法使用PointInside:withEvent:进行判断,那么就没法进行子视图的遍历。当去掉这个语句的时候,触摸事件就不可能进到子视图中了,除非你在方法中直接返回子视图的对象。这样你在调试的过程中就会发现,每次你点击一个view都会先进入到这个view的父视图中的hitTest方法,然后调用super的hitTest方法之后就会查找pointInside是否返回YES如果是,则就把消息传递个子视图处理,子视图用同样的方法递归查找自己的子视图。所以从这里调试分析看,hitTest方法这种递归调用的方式就一目了然了。
这个只是说了调试中吻合官方文档中解释的部分,但是还有一个问题,就是每个view中hitTest总要调用三个,这个查找了API和很多资料都没有找到解决的方法,然后google了以下在overflowstack中发现了有人这样解释:Thereareindeed3callstohitTest.Itisnotclearwhy,
butwecansurmisebythetimestampsontheevent
thatthefirsttwocallsaretodowithcompletingthepreviousgesture-
thosetimestampsarealwaysveryclosetowhenevertheprevioustouchhappened,
andwillbesomedistancefromthecurrenttime.(确实有3次调用hitTest,不清楚为什么,但是前两次调用时里面的UIEvent中的timestamps属性和上一次已经完成的手势有关。这些时间timestamps是如此的接近无论先前的触摸什么时候发生,并且和系统当前的时间有一定的间隔)。看到这里我想到了,”EventHandlingGuideforiOS”中曾经解释,如何区分单击和双击的区别,用的方法很简单,代码如下:
所以区别这两个手势的思想,就是判断tapcount如果发现touchEnd的时候tapcount是2就取消第一次执行的动作。但是这一点是否想过,苹果公司是如何判断tapcount的,比如说我在屏幕上按了下去,过了一分钟后松开,那么在touchEnd方法中捕捉到的touch事件和我点击一下屏幕就起来一样么?答案是不一样的,可以写程序亲自试验以下,按下去一分钟再松开,这里没必要一分钟了,就几秒也足够了,你会发现再touchEnd中tapCount为0,而点击一下松开的tapCount为1。还有一种情况就是双击,如果我双击间隔的时间超过大概4,5秒钟,再次侦测touchEnd中的tapCount就会发现是1,而正常的双击tapCount为2。这里和hitTest执行三次,并且前两次记录的时间是上一次触摸手势的时间,后一次才是本次触摸手势的时间,有没有关系,官方没有任何解释,这里也只能臆测。是不是用来区分上面所说的情况,也就是说根据这个事件timestamp来改变UITouch中tapCount的次数,还希望那位高手给予解释。所以上面提到的UIEvent,这个事件为何能向苹果官方解释的那样流动,这里也就可见一斑了。
最后推荐俩本iphone开发的书籍,非常适合初学者使用。一本是iphone开发秘籍,另外一本是Core.AnimationSimplified。我的空间里有这两本书的资源,不过都是英文原本的,有兴趣的可以看下(http://download.csdn.net/source/3347531,http://download.csdn.net/user/mengtnt)
分享到:
相关推荐
资深大牛全方位剖析: UI相关 Runtime Runloop OC底层 Block Animation 音视频学习从零到整(2) 音视频学习从零到整(1) 性能优化 网络相关 探讨iOS 中图片的解压缩到渲染全过程 数据结构与算法 数据安全及加密 设计...
一个简单的 UIView 显示一个水平的“温度计”,在一条圆线上使用两种不同的颜色表示一个值。 该实现使用了几个带有圆角和背景颜色的子层; 虽然尚未对此实现进行概要分析,但从理论上讲,这使其在资源使用方面既...
audiounitjs, 带有HTML用户界面...audiounit.js 是一个用于为 OS X 和iOS创建音频软件( 。效果,分析器和合成器)的Xcode项目脚手架。 音频处理代码用 C 编写,UI代码是用 HTML 。CSS和Javascript编写的。 编写音频处理
自动跟踪事件#####触摸 touchesBegan:withEvent:这包括任何 UIView 子类的所有触摸,包括按钮。 #####手势 ...
ios核心动画,包括:CABasicAnimation基础动画、CAKeyframeAnimation帧动画、CATransition过度动画、CAAnimationGroup...本代码主要对核心动画进行描述分析、并与UIView动画进行对比,注释都非常清晰,希望对大家有用!
一、分析与说明 1.1 分析界 效果 当鼠标在图片上拖动的时候,图片上有一个折叠的效果. 这种折叠效果其实就是图片的上半部分绕着X轴做一个旋转的操作. 我们图片的旋转都是绕着锚点进 旋转的.所以如果是一张图片的,办...
适用于UI和CoreData的iOS层次结构查看器iOS Hierarchy Viewer允许开发人员调试UIView和CoreData模型的层次结构。 如果布局计算存在问题,则可以通过在浏览器中内省视图的实时预览来轻松找到它们。 如果您的数据表现...
作者Jerrylingit/PieChartDemo,思路分析 看到下面这个效果,切入点应该是怎么生成这个饼状图,然后再让饼状图旋转。 rotatePieChartDemo.gif 怎么生成饼状图(UIBezierPath) 首先是要新建一个CAShapeLayer,...
而且通常来说我们使用的最多的是TouchUpInside方式的点击事件,所以为了方便使用,我对UIButton/UIView的点击事件进行了扩展。 使用 和之前一样,我们先来看看扩展之后如何使用 oc版本 [_btn1 setOnclick:^{ ...
二、分析 寻找左边的规律,每一个uiview的x坐标和y坐标。 三、实现思路 (1)明确每一块用得是什么view (2)明确每个view之间的父子关系,每个视图都只有一个父视图,拥有很多的子视图。 (3)可以先尝试逐个的添加格子...
因为我这也报了这个警告,所以把解决方法写到这个地方看是否其他人用的到,具体解决方法:...问题分析:iOS8在调用系统相机拍照时,会有一两秒的停顿,然后再弹出UIImagePickConroller,IOS7是没有这个问题的,在百度找
iOS-UI分析利器--Reveal 在 iOS 开发中,我们有时很希望有一款类似 Web 开发中的 UI Debug 工具,让我们能够实时查看 UI 的结构,还可以实时更改某个 UIView 的位置和大小的相关属性值查看效果。这里我们发现原来真...
19.2.1 在uiview上绘制图形293 19.2.2 在位图上绘制图形294 19.3 绘制路径295 19.3.1 结束路径296 19.3.2 创建可重用路径296 19.3.3 绘制矩形297 19.4 设置图形状态298 19.4.1 设置颜色298 19.4.2 ...
第4章“UIView与控件”。学习视图和控件之间的关系以及应用界面的建构层次。然后对标签、按钮、文本框、导航栏等基本控件的介绍。接下来是屏幕布局的内容以及一个较为复杂的控件—选择器,最后是关于iOS6中的...
而不是针对实现编程1.6.2 @protocol与抽象基类1.6.3 对象组合与类继承1.7 本书用到的对象和类1.7.1 类图1.7.2 对象图1.8 本书如何安排模式的讲解1.9 总结第2章 案例分析:设计一个应用程序2.1 想法的概念化2.2 界面...