iOS学习纪事——自己实现放大镜视图

 

为什么要自己实现一个放大镜视图呢,因为上一篇中说的TextKit的问题,所以正好趁这个机会来自己做些iOS中本来就有的东西,比如文字选择效果、编辑菜单什么的,权当是练习了。

 

标题虽然说是自己实现,不过还是参照了别人的先进经验啦,见这里。这个实现的基本原理,是新建一个视图(MagnifierView)并显示,然后将要放大的视图的图层通过放大平移渲染在这个视图中。对我来说,其中最关键的代码是这个:

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context,1*(self.frame.size.width*0.5),1*(self.frame.size.height*0.5));
    CGContextScaleCTM(context, 1.5, 1.5);
    CGContextTranslateCTM(context,-1*(touchPoint.x),-1*(touchPoint.y));
    [self.viewToMagnify.layer renderInContext:context];
}

 

 

但是秉着精益求精的态度,这个实现还有几个瑕疵:

1. 当手指移动到屏幕下方时,会出现下图所示情况。因为放大镜视图(MagnifierView)中要显示的内容已经超出了屏幕范围。

 

2. 状态栏会挡住放大镜视图,并且,当手指移动到屏幕最上面时,放大镜也出了屏幕范围因而看不到放大的内容(虽然即使不超出也可能被手指挡住……)

 

3. 从代码可以看出,被放大的只是那个特定的视图(viewToMagnify)及该视图的子视图。所以不难想像,如果视图不是覆盖整个屏幕,则会出现问题,balabalabala……例子我就不举了~

 

 

好了,下面是我的解决方案。我用Xcode5和storyboard重写了项目,并且代码放到了GitHub

1. 对于第一点问题,我想到的方法是,在放大镜视图中加一个子视图(图层),在子视图(图层)中渲染要放大的内容,这样当手指移动到屏幕下面时就不会出现真空地带。添加子视图似乎有点麻烦,并且我及时发现了一个CALayer的委托方法:-drawLayer:inContext:(非正式协议方法),利用这个方法可以很方便的绘制子图层。于是这个问题愉快的解决了。不过值得注意的一点还有CALayer的contentsScale属性,如果是Retina屏,需要将该值设为2。

效果如下图:

 

2. 放大镜视图超出屏幕上方这个很好解决,不多说。而对于状态栏的问题,解决方法是让放大镜视图继承自UIWindow而不是UIView,并且将windowLevel设为UIWindowLevelAlert。具体可以看我的代码。

 

3. 第三点问题也简单,只需做3个小改动,即将:

self.magnifierView.viewToMagnify = self;

改为:

self.magnifierView.viewToMagnify = self.window;

以及另外两个地方的:

self.magnifierView.pointToMagnify = [[touches anyObject] locationInView:self];

改为:

self.magnifierView.pointToMagnify = [[touches anyObject] locationInView:self.window];

效果图:

 

 

以上,经过这一番修改差不多没什么问题了。不过iOS系统本身的放大镜可以连状态栏一起放大,我现在还不知道怎么实现。。。

 

posted @ 2014-02-27 21:38  Sinkup  阅读(2630)  评论(0编辑  收藏  举报