iOS自定义控件开发梳理总结

2020-01-18 17:13:17于海丽


-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
 if (!self.isUserInteractionEnabled || self.hidden || self.alpha<=0.01) {
  return nil;
 }
 CGRect touchRect = CGRectInset(self.bounds, -20, -20);
 if (CGRectContainsPoint(touchRect, point)) {
  for (UIView *subView in [self.subviews reverseObjectEnumerator]) {
   CGPoint convertedPoint = [subView convertPoint:point toView:self];
   UIView *hitTestView = [subView hitTest:convertedPoint withEvent:event];
   if (hitTestView) {
    return hitTestView;
   }
  }
  return self;
 }
 return nil;
}

二、穿透传递事件。

假设有两个view,viewA和viewB,viewB完全覆盖viewA,我们希望点击viewB时能响应viewA的事件。我们重写这个viewA的hitTest:withEvent:方法,不继续遍历它的子视图,直接返回自身。代码如下:


-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
 if (!self.isUserInteractionEnabled || self.hidden || self.alpha<=0.01) {
  return nil;
 }
 if ([self pointInside:point withEvent:event]) {
  NSLog(@"in view A");
  return self;
 }
 return nil;
}

回调机制

在自定义控件开发中,需要向它的父类回传返回值。比如一个存放按钮的自定义控件,需要在上层接收按钮点击事件。我们可以使用多种方式回调消息,比如target action模式、代理、block、通知等。

Target-Action

Target-Action是一种设计模式,当事件触发时,它让一个对象向另一个对象发送消息。这个模式我们接触的比较多,如为按钮绑定点击事件,为view添加手势事件等。UIControl及其子类都支持这个机制。Target-Action 在消息的发送者和接收者之间建立了一个松散的关系。消息的接收者不知道发送者,甚至消息的发送者也不知道消息的接收者会是什么。

基于 target-action 传递机制的一个局限是,发送的消息不能携带自定义的信息。iOS 中,可以选择性的把发送者和触发 action 的事件作为参数。除此之外就没有别的控制 action 消息内容的方法了。

举个例子,我们使用Target-Action为控件添加一个单击手势。


  UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(refresh)];
  [_imageView addGestureRecognizer:tapGR];

- (void)refresh{
 NSLog(@"Touch imageView");
}

代理

代理是一种我们常用的回调方式,也是苹果推荐的方式,在系统框架UIKit中大量使用,如UITableView、UITextField。

优点:1,代理语法清晰,可读性高,易于维护 ;2,它减少了代码耦合性,使事件监听与事件处理分离;3,一个控制器可以实现多个代理,满足自定义开发需求,灵活性较高;

缺点:1,实现代理的过程较繁琐;2,跨层传值时加大代码的耦合性,并且程序的层次结构也变得混乱;3,当多个对象同时传值时不易区分,导致代理易用性大大降低;