可以自己寫UIButton分類重寫按鈕響應(yīng)鏈方法惫皱,結(jié)合關(guān)聯(lián)對象設(shè)置屬性來控制button的具體實現(xiàn)方法左电。
- hitTest中的內(nèi)部實現(xiàn)面試時可能會用到
// 重新實現(xiàn)hittest方法,實現(xiàn)圓形按鈕點擊范圍
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.userInteractionEnabled||self.hidden||self.alpha<0.01) {
return nil;
}
if ([self pointInside:point withEvent:event]) {
// 遍歷當前對象的子視圖
__block UIView *hit = nil;
[self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// 坐標轉(zhuǎn)換
// convertPoint: toView:是(調(diào)用者的point+convertpoint)- toview的point
// convertPoint: fromView:是(fromView的point+convertpoint)- 調(diào)用者的point
CGPoint convertPoint = [self convertPoint:point toView:obj];
// 調(diào)用子視圖的hittest方法
hit = [obj hitTest:convertPoint withEvent:event];
// 如果找到了接受事件的對象,就停止遍歷
if (hit) {
*stop=YES;
}
}];
if (hit) {
return hit;
}else{
return self;
}
}else{
return nil;
}
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// 點擊的點
CGFloat x1=point.x;
CGFloat y1=point.y;
// 中心
CGFloat x2=self.frame.size.width/2;
CGFloat y2=self.frame.size.height/2;
// 平方差公式
double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
if (dis<=self.frame.size.width/2) {
return YES;
}else{
return NO;
}
}
針對超出父view之外的部分垦江,比如按鈕點擊無響應(yīng)問題
原因:響應(yīng)鏈會先判斷點是否在父view范圍內(nèi)嗓化,在父view范圍內(nèi)就正序遍歷子視圖判斷哪個來響應(yīng)棠涮,不在就不響應(yīng)該點擊事件。
//超出父層的按鈕部分點擊無效果 --- 可通過父類view重寫如下方法判斷子view能否響應(yīng)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *subV in self.subviews) {
if ([subV isKindOfClass:[UIButton class]]) {
UIButton *btn=(UIButton *)subV;
if (CGRectContainsPoint(btn.frame, point)) {
return YES;
}
}
}
BOOL ss=[super pointInside:point withEvent:event];
return ss;
}
在來個CoreAnimation運動動畫的btn無法點擊辦法解決:
自定義子view和自定義父view分別重寫- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event和- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 方法
自定義父view實現(xiàn):
//超出父層的按鈕部分點擊無效果 --- 可通過重寫如下方法盤點子view能否響應(yīng)時間
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.userInteractionEnabled||self.hidden||self.alpha<0.01) {
return nil;
}
if ([self pointInside:point withEvent:event]) {
// 遍歷當前對象的子視圖
__block UIView *hit = nil;
[self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// 看情需要否轉(zhuǎn)換坐標
// 坐標轉(zhuǎn)換
// convertPoint: toView:是(調(diào)用者的point+convertpoint)- toview的point
// convertPoint: fromView:是(fromView的point+convertpoint)- 調(diào)用者的point
// CGPoint convertPoint = [self convertPoint:point toView:obj];
// 調(diào)用子視圖的hittest方法
hit = [obj hitTest:point withEvent:event];
// 如果找到了接受事件的對象刺覆,就停止遍歷
if (hit) {
*stop=YES;
}
}];
if (hit) {
return hit;
}else{
return self;
}
}else{
return nil;
}
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *subV in self.subviews) {
if ([subV isKindOfClass:[UIButton class]]) {
UIButton *btn=(UIButton *)subV;
// 通過判斷子view的運動layerframe來確定點擊范圍
if (CGRectContainsPoint(btn.layer.presentationLayer.frame, point) ) {
return YES;
}
}
}
BOOL ss=[super pointInside:point withEvent:event];
return ss;
}
自定義子view實現(xiàn):
// 通過判斷子view的運動layerframe來確定點擊范圍
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *vc=[super hitTest:point withEvent:event];
if (CGRectContainsPoint(self.layer.presentationLayer.frame, point) ) {
return self;
}
return vc;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL ss=NO;
if (CGRectContainsPoint(self.layer.presentationLayer.frame, point) ) {
ss=YES;
}else{
ss=[super pointInside:point withEvent:event];
}
return ss;
}
最后送個仿支付寶上下不規(guī)則浮動泡泡的動畫:
CABasicAnimation *opacityAnim1 =[CABasicAnimation animationWithKeyPath:@"opacity"];
opacityAnim1.fromValue = [NSNumber numberWithDouble:1];
opacityAnim1.toValue =[NSNumber numberWithDouble:.5];
opacityAnim1.duration=5+(double)arc4random()/0x100000000;// 修改漸變動畫時間
opacityAnim1.repeatCount=MAXFLOAT;
opacityAnim1.delegate=self;
opacityAnim1.fillMode =kCAFillModeForwards;
opacityAnim1.autoreverses=YES;
opacityAnim1.removedOnCompletion=NO;
opacityAnim1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[btn.layer addAnimation:opacityAnim1 forKey:@"LightopacityAnim"];
CABasicAnimation *shake1Animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
double fw1=50+(double)arc4random()/0x100000000;// 修改位移動畫距離
shake1Animation.duration=5+(double)arc4random()/0x100000000;// 修改位移動畫時間
shake1Animation.fromValue = [NSNumber numberWithFloat:-fw1];
shake1Animation.toValue = [NSNumber numberWithFloat:fw1];
shake1Animation.autoreverses = YES;
shake1Animation.repeatCount=MAXFLOAT;
shake1Animation.fillMode =kCAFillModeForwards;
shake1Animation.removedOnCompletion=NO;
shake1Animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[btn.layer addAnimation:shake1Animation forKey:nil];