iOS Programming 5(Redrawing and UIScrollView)
在上一篇博客中,我们创建了一个画同心圆的app,这篇博客将继续在那上面扩展,当用户在屏幕上点击的时候同心圆会改变颜色.此外,还将在app里面加上UIScrollView,让用户通过scroll的方式浏览比屏幕本身大的view.
改变同心圆颜色
既然是通过点击来改变同心圆的颜色,那么我们肯定会想到用touch event来实现,在用户touch之后需要改变颜色,我们可以通过创建一个公有变量,然后在touch方法里改变他的颜色. 我们现在项目的格局如下:

首先我们在BNRHypnosisterView.m的头部创建一个property文件:
1 2 3 4 5 6 7 8 9 | |
在这里创建property而不是在header文件里面创建的原因是隐藏这个变量.一个类的header文件是对所有类可见,一种默认的做法是如果变量是定义在header文件里面,那么就表示他可以和其他所有的类互动,如果我想要这个变量或者方法只在这个类中使用,那么可以把它定义在.m的category里面.这相当于对其他类隐藏了这个变量或方法,即使其子类都不能看到.
声明完之后就应该开始定义了,我们可以到initWithFrame方法里给它首先赋予一个默认值:
1 2 3 4 5 6 7 8 9 10 | |
这样在程序启动的时候同心圆的颜色是灰色.接下来就应该实现touch even了, 当用户点击后就改变circleColor的颜色我们通过实现默认的touchesBegan方法来实现.
1 2 3 4 5 6 7 8 | |
上面这个方法就是在每次用户点击的时候都重新开始算rgb在randomColor中的分量,然后得到一个新的randomColor并把它赋值给circleColor.这样circleColor的颜色就变了,现在我们可以运行看看效果:

我们发现无论怎么点击屏幕,颜色都不会改变,这是为什么呢?这里有两个原因:
- UIView的drawRect方法默认情况下只在加载的时候被调用,所以无论我们怎么点击屏幕,这个方法都不会被再次调用,所以所有的view都没有被重新render.
- 在drawRect方法里面没有改变同心圆的颜色,改变的代码如下:
1 2 | |
这里又涉及到iOS的一种机制:run loop. 它指的是当iOS app 在运行的时候,他会开始一个run loop,这个loop是专门用来监听事件的.当一次事件发生时(例如touch),run loop会找到相应的handler来处理这次事件,当这个事件被处理后,run loop继续执行. 在我们这个程序中,当run loop发现touch事件时,会停下来调用touchesBegan方法处理它,在处理完后重新回到tun loop中.在重新回到run loop后,它会检查那些在上次执行handler之后有改变并且需要重新render的view,然后run loop会发送drawRect:方法给这些view,然他们重新去render.但是为什么我们在点击屏幕后view并没有被重新render呢?原来这是因为需要被重新render的view不是系统默认的,如果他们是默认的(例如UIButton, UIText),render会自动执行,否则我们需要调用view的setNeedsDisplay方法来让他重新render.在touchesBegan:方法的最后一句,我们看到circleColor被重新赋值(其实是它的setter方法被调用了),那么我们可以重载它的setter方法,并在里面调用setNeedsDisplay方法.
1 2 3 4 | |
再次运行,一切OK.

使用UIScrollView
Scroll view通常是为比屏幕更大的view准备的,这样就能通过上下左右滚动来查看完整的图片.之前我们是直接把当前的view加到UIWindow中,不过为了实现scroll view,我们需要把当前view加到scroll view中,然后再把这个scroll view加到UIWindow中去.

然后到app delegate的didFinishLaunchingWithOptions里加上如下代码:
1 2 3 4 5 6 7 8 9 10 | |
首先建立一个屏幕大小的CGRect作为UIScrollView的显示范围,然后建立一个两倍屏幕大小的CGRect作为view的显示范围,最后把view加到UIScrollView中.显示的效果如下:

最后,我们可以把它做的更好看一些,我们给UIScrollView加两个view,并让他们在不同的屏幕显示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
其中scrollView.pagingEnabled = YES的意思是在左右滑动的时候有翻页的效果,屏幕不会停在两个view的中间.
