某些情况下我们需要按钮有不规则的形状,在这些形状内点击才有响应,例如下面的图片中:
图片中红线圈出的两处都是用按钮做的,按钮的实际布置是上面第二张图所画的那样,所有按钮都是矩形的,但是中间的按钮和一圈的转盘形状都不可能用矩形,否则点击的时候难免相互影响。
那么如何自定义按钮点击的有效区域呢,其实很简单,只要重写一个函数即可:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
系统发生触摸事件的时候会从window到父控件到子控件一个个检测触摸点是否在其中,如果在其中,则返回YES,最后返回YES的子控件作为响应事件的控件。
我们只要重写这个方法,在其中判断,是否点击了我们想要的区域,是的话就返回YES,否则返回NO,这样就实现了自定义点击的有效区域了。注意,这边并没有改变按钮的形状,按钮还是矩形的按钮,只是改变了按钮中响应区域而已。
那么接下来的问题就是,怎么判断一个点是否在一个不是矩形的区域中呢,这边可以使用UIBezierPath的方法:
- (BOOL)containsPoint:(CGPoint)point;
我们可以先根据想要的形状绘制一条path,然后判断调用上面的方法去判断即可。
例如,我自定义了上面圆盘中心的圆形按钮,重写了函数,实现只有点击圆形区域按钮才有用。
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
//首先调用父类的方法确定点击的区域确实在按钮的区域中
BOOL res = [super pointInside:point withEvent:event];
if (res) {
//绘制一个圆形path
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.bounds];
if ([path containsPoint:point]) {
//如果在path区域内,返回YES
returnYES;
}
returnNO;
}
returnNO;
//首先调用父类的方法确定点击的区域确实在按钮的区域中
BOOL res = [super pointInside:point withEvent:event];
if (res) {
//绘制一个圆形path
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.bounds];
if ([path containsPoint:point]) {
//如果在path区域内,返回YES
returnYES;
}
returnNO;
}
returnNO;
}
圆盘周围的按钮则比较复杂一些,我取巧的只画了一个三角形,这样效果几乎跟弧形差不多。
//自定义圆盘周围星座按钮的点击区域
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL res = [super pointInside:point withEvent:event];
if (res) {
//画了一个三角形的path,形状跟弧形接近,点击效果几乎没什么区别
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(self.bounds.size.width/2,self.bounds.size.height)];
[path addLineToPoint:CGPointMake(0,0)];
[path addLineToPoint:CGPointMake(self.bounds.size.width,0)];
[path addLineToPoint:CGPointMake(self.bounds.size.width/2,self.bounds.size.height)];
if ([path containsPoint:point]) {
returnYES;
}
returnNO;
}
returnNO;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL res = [super pointInside:point withEvent:event];
if (res) {
//画了一个三角形的path,形状跟弧形接近,点击效果几乎没什么区别
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(self.bounds.size.width/2,self.bounds.size.height)];
[path addLineToPoint:CGPointMake(0,0)];
[path addLineToPoint:CGPointMake(self.bounds.size.width,0)];
[path addLineToPoint:CGPointMake(self.bounds.size.width/2,self.bounds.size.height)];
if ([path containsPoint:point]) {
returnYES;
}
returnNO;
}
returnNO;
}
最后,对自定义按钮重写以上方法后按钮的有效区域就像下图所示的用蓝色和绿色框线标注出来的那样,只有在这个区域内点击才有效: