ViewChaos我的UI调试之道(原理篇)

586 查看

上一篇文章我给大家展示了ViewChaos强大的UI调试能力,相信有部分读者会对它的实现机制有兴趣,这一篇我给大家讲一下开发这个工具碰到的坑和一些功能实现的原理。如果你还没有看上一篇ViewChaos我的UI调试之道效果篇,请先看这篇文章。另外Github地址为
ViewChaos,请大家赏脸给个Star,我将继续写更好的文章和开源项目。

怎么才能在不写一行代码的情况下启动ViewChaos

这个问题其实并不难,相信各位读者知道在Objective-C里,有一个方法叫load,利用它,在里面加上自己想要的代码,很容易便能在APP启动的时侯加入自己想要的东西

但问题是Swift已经没有这个方法了,所以只好用另一个办法,就是initialize方法,这个方法可以放在extension里面,当APP里的UIWindow类每实例化一次,就会调用这个方法。所以我们还要加入单次分派,来保证只调用一次。

这样ViewChaos就能随系统启动而不用写一行代码,但这里存在的问题是这样如何后来APP开发者也想写这种功能,如果他想用扩展UIWindow来实现自己的功能,会导致冲突。

怎么才能在Debug模式下启用功能,而Release模式下自动关闭

这个很简单,上一段代码里我用了宏,这个宏说明只有在DEBUG模式下才会编译里面的代码。所以Release自然就没有该功能了,但目前是Swift其实并不支持宏,而是通过Swift Compiler-Custom Flags的方式来实现的,在里面的Other Swift Flags里面加入-DDEBUG标记就行了,

将Other Swift Flags的Debug加上—DEBUG

怎么添加那个小圆球

启动会有小圆球

我们在UIWindowinitialize方法中使用了Method Swizzle,这里就不解释什么是Method Swizzle了,我在这里替换了四个方法,其中makeKeyAndVisible方法是APP启动时必定会调用的一个方法。我替换了这个方法,在里面加入了这个小球

如果启动摇一摇功能

见上面代码添加UIApplication.sharedApplication().applicationSupportsShakeToEdit = true就能启动摇一摇了,当然,关闭也可以用这个属性。然后再在
public override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?)方法里处理事件就OK了,当然苹果还提供了

这两个方法。

如何放大View并获取该点的颜色

这个功能比较有意思,首先在放大镜模式下App里面的点击和触摸事件都要让它失效,不然会起冲突。我定义了一个叫ZoomViewBrace的View。它的作用是起承担override func touchesMoved(touches: Set, withEvent event: UIEvent?)事件的,这样就可以屏蔽掉原页面里的点击和触摸事件,就可以对该View做放大操作了。

放大的View名叫ZoomView,它是一个UIWindow对象,它有个viewToZoom的属性,当我们用手触摸时,截图的View传给该属性,然后再将坐标点也传进去,再调用setNeedsDisplay方法,
ZoomView就会自动调用下面的方法,将放大自己1.5倍后再绘制出来。

这样就有放大效果了

然后就是该点颜色显示功能,实现它的步骤是这样的,首先获取viewToZoom的那个View,生成一张截图,再转化成UnsafeMutablePointer对象,这里面包含了该截图的颜色信息。接下来就是根据坐标点提取RBG值了。这样就能获取该点颜色了。
这里的代码稍微有点长,就不写出来了,建议有兴趣的读者看源码。

如何显示所有View的边框和透明值

边框模式

透明模式

这个其实非常简单,就用一个递归加上循环不停在获取UIWindow下里面所有的View的位置,再生成一个和其位置一样的View,显示这个View的边框,再插入这些VIew
到UIWindow就OK啦,透明度也一样。

如果获取绿色小球下的View

这个ViewChaos最为核心的功能;首先,我定义了一个 arrViewHit的数组,它是一个[UIView]对象,它的作用是用来保存位于该小球下的所有的View,当小球上touchesBegain事件触发或者touchesMove事件触发时,不停地调用topView方法。

topView就是取arrViewHit里面的最后一个View,最后一个View就是位于小球下面的最上面的View。hitTest这个方法会将所有位置小球下的View放进arrViewHit里面。
下面看看hitTest这个方法