iOS開(kāi)發(fā)中會(huì)使用到自定義UIView,下面是我在學(xué)習(xí)過(guò)程中寫(xiě)的一個(gè)自定義UIView:
#import "BNRHypnosisView.h"
@interface BNRHypnosisView()
@property(nonatomic, strong) UIColor *circleColor;
@end
@implementation BNRHypnosisView
- (void)setCircleColor:(UIColor *)circleColor {
_circleColor = circleColor;
[self setNeedsDisplay];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.circleColor = [UIColor lightGrayColor];
//self.userInteractionEnabled = YES; //開(kāi)啟用戶交互仍然不能響應(yīng)touchesBegan事件
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef cgContext = UIGraphicsGetCurrentContext();
CGRect bounds = self.bounds;
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
UIBezierPath *path = [[UIBezierPath alloc] init];
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
[path moveToPoint:CGPointMake(center.x + currentRadius, center.y)];
[path addArcWithCenter:center radius:currentRadius startAngle:0.0 endAngle:M_PI*2.0 clockwise:YES];
}
[self.circleColor setStroke];
path.lineWidth = 10.0;
[path stroke];
CGContextSaveGState(cgContext);
CGContextSetShadow(cgContext, CGSizeMake(4, 7), 3);
UIImage *logoImage = [UIImage imageNamed:@"logo.png"];
[logoImage drawInRect:rect];
CGContextRestoreGState(cgContext);
}
- (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;
}
@end
在AppDelegate中使用這個(gè)自定義UIView,代碼如下所示:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow *window in windows) {
if(window.rootViewController == nil){
UIViewController *vc = [[UIViewController alloc]initWithNibName:nil
bundle:nil];
window.rootViewController = vc;
}
}
CGRect firstFrame = self.window.bounds;
BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];
[self.window addSubview:firstView];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
看似很完美的代碼,但是一運(yùn)行,無(wú)法響應(yīng)touchesBegan事件,開(kāi)始以為是沒(méi)有開(kāi)啟用戶交互,加上開(kāi)啟用戶交互self.userInteractionEnabled = YES,仍然沒(méi)用,后來(lái)有人說(shuō)是這個(gè)自定義UIView視圖被遮擋,導(dǎo)致無(wú)法響應(yīng)觸摸事件,給了我開(kāi)啟視圖調(diào)試器調(diào)試看看的建議,果然,開(kāi)啟視圖調(diào)試器看到這個(gè)自定義UIView確實(shí)被遮擋了,如下圖所示:
該怎么解決呢?有人說(shuō)是[self.window makeKeyAndVisible]出了問(wèn)題,他會(huì)把window的rootViewController放到最前面,但我想這肯定是沒(méi)讀懂官方文檔對(duì)makeKeyAndVisible方法的解釋?zhuān)缦聢D所示:
它是UIWindow對(duì)象的一個(gè)實(shí)例方法,是把當(dāng)前window置于其他window的前面,也就是說(shuō)是把整個(gè)包含了我的自定義UIView的window對(duì)象置于最前面,所以,即使注釋掉這行代碼,仍然無(wú)法解決我的自定義UIView被遮擋的問(wèn)題。
那么問(wèn)題出在哪里呢?對(duì),問(wèn)題就出在AppDelegate的下面這段代碼中:
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow *window in windows) {
if(window.rootViewController == nil){
UIViewController *vc = [[UIViewController alloc]initWithNibName:nil
bundle:nil];
window.rootViewController = vc;
}
}
根據(jù)上圖所示官方文檔對(duì)rootViewController的說(shuō)明,可以知道設(shè)置了window.rootViewController會(huì)給window設(shè)定一個(gè)content view。根據(jù)視圖調(diào)試器顯示出來(lái)的內(nèi)容,這個(gè)content view應(yīng)該也就是一個(gè)UIView。所以當(dāng)這個(gè)自定義的UIView添加到self.window上,代碼如下所示:
CGRect firstFrame = self.window.bounds;
BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];
[self.window addSubview:firstView];
這個(gè)自定義UIView就會(huì)被rootViewController設(shè)定的content view遮擋,就不能響應(yīng)觸摸事件了。
因此,解決這個(gè)問(wèn)題修改后的關(guān)鍵代碼如下所示:
CGRect firstFrame = self.window.bounds;
BNRHypnosisView *firstView = [[BNRHypnosisView alloc] initWithFrame:firstFrame];
[self.window.rootViewController.view addSubview:firstView];