本节,继续开发Hypnosister应用,当用户触摸视图时,圆形的颜色会改变。为了改变颜色,BNRHyponsister需要重新绘制自己。
(1)声明一个属性,用来表示圆形的颜色
在BNRHypnosister.m的类扩展部分声明属性,并在initWithFrame:方法中初始化
@interface BNRHypnosister()
@property(strong,nonatomic)UIColor *circleColor;
@end
@implementation BNRHypnosister
- (instancetype)initWithFrame:(CGRect)frame
{
self=[super initWithFrame:frame];
if(self)
{
self.backgroundColor=[UIColor clearColor];
self.circleColor=[UIColor lightGrayColor];
}
return self;
}
在drawRect:方法中修改设置线条颜色的代码,使用circleColor作为线条颜色。
//[[UIColor lightGrayColor] setStroke];
[self.circleColor setStroke];
(2)编写视图触摸改变颜色的代码
当用户触摸视图时,视图会受到touchesBegan:withEvent: 消息,用来处理触摸事件
在BNRHypnosister.m中对这个方法进行覆盖
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"%@ was touched",self);
float red=arc4random()%100/100.0;
float green=arc4random()%100/100.0;
float blue=arc4random()%100/100.0;
UIColor *randomColor=[UIColor colorWithRed:red
green:green
blue:blue
alpha:1.0];
self.circleColor=randomColor;
}
**这里强调一点:
触摸视图并没有触发触摸事件,是因为需要把我自定义的UIView添加到这里1,而不是2
rootViewController会给window设定一个content View,也是UIView类,所以将我自定义的UIView给遮挡了,导致无法触发touchesBegan事件
[self.window.rootViewController.view addSubview:firstView]; //1
[self.window addSubview:firstView]; //2
此时构建项目,点击任意位置 控制台输出触摸事件,但是颜色并未改变。
应用将控制权交回给运行循环时,首先检查有没有等待重绘的视图,向它们发送drawRect:消息。
这是因为我们还需要进行重绘,发送一次drawRect:消息。
(3)进行重绘标记
为了标记视图需要重绘,必须向其发送setNeedsDisplay消息。
做法是:为circleColor属性实现自定义的存方法,当circleColor改变时(就是调用了存方法的时候)向视图发送setNeedsDisplay消息。
- (void)setCircleColor:(UIColor *)circleColor
{
_circleColor=circleColor;
[self setNeedsDisplay];
}
点击视图可以换色了。
(4)使用UIScrollView
添加一个UIScrollView对象,使其成为应用窗口的子视图,然后再将BNRHypnosister作为子视图加入UIScrollView对象。
UIScrollView对象的尺寸就是这个镜头的尺寸,能拍摄的范围是由属性 contentSize决定的。创建一个超大尺寸的BNRHyponsister对象并将其加入一个UIScrollView对象,然后把这个UIScrollView对象加入窗口。
//创建两个结构作为 uiscrollview和bnrhtpnosister对象的frame
CGRect screenRect=self.window.bounds;
CGRect bigRect =screenRect;
bigRect.size.height*=2.0;
bigRect.size.width*=2.0;
//分别设置两个对象
UIScrollView *scrollView=[[UIScrollView alloc] initWithFrame:screenRect];
[self.window.rootViewController.view addSubview:scrollView];
BNRHypnosister *hypnosisView=[[BNRHypnosister alloc] initWithFrame:bigRect];
[scrollView addSubview:hypnosisView];
//设置取景范围
scrollView.contentSize=bigRect.size;
[self.window makeKeyAndVisible];
**这里注意self.window.rootViewController.view 道理同之前所说,否则触摸事件不会被触发。
可以拖动来查看大尺寸的背景其余部分。
(5)拖动与分页
UIScrollView对象还可以滑动显示所有加入UIScrollView对象的子视图
把BNRHypnosister对象的尺寸改回与屏幕的尺寸相同,然后再创建一个BNRHypnosister对象,并加入UIScrollView对象。此外将UIScrollView的contentSize宽度设置为屏幕宽度的两倍。
代码如下:
//创建两个结构作为 uiscrollview和bnrhtpnosister对象的frame
CGRect screenRect=self.window.bounds;
CGRect bigRect =screenRect;
bigRect.size.width*=2.0;
//分别设置三个对象
UIScrollView *scrollView=[[UIScrollView alloc] initWithFrame:screenRect];
[self.window.rootViewController.view addSubview:scrollView];
BNRHypnosister *hypnosisView=[[BNRHypnosister alloc] initWithFrame:screenRect];
[scrollView addSubview:hypnosisView];
screenRect.origin.x+=screenRect.size.width;
BNRHypnosister *anotherView=[[BNRHypnosister alloc] initWithFrame:screenRect];
[scrollView addSubview:anotherView];
//设置取景范围
scrollView.contentSize=bigRect.size;
[self.window makeKeyAndVisible];
此时左右拖动屏幕看到两个对象,有可能出现连接部分。
有些时候我们需要让镜头的边和某个视图对齐,加入一行代码如下
[scrollView setPagingEnabled:YES];
构建并运行,拖动屏幕直到能看到两个对象的连接部分,松开之后会自动把镜头切换到一个对象上。