Objective c 允许与另一个UIView下的UIView交互

Objective c 允许与另一个UIView下的UIView交互,objective-c,ios,cocoa-touch,Objective C,Ios,Cocoa Touch,有没有一种简单的方法可以允许与位于另一个UIView下的UIView中的按钮进行交互?如果按钮顶部的UIView中没有实际对象 例如,目前我有一个UIVIEW(A),在顶部有一个对象,在屏幕的底部有一个对象,中间没有任何东西。这位于另一个UIVIEW的顶部,中间有按钮(B)。但是,我似乎不能与B.中的按钮交互。 我可以看到B中的按钮-我已经将A的背景设置为clearColor-但是B中的按钮似乎没有收到触动,尽管事实上这些按钮上面没有来自A的对象 编辑-我仍然希望能够与俯视图中的对象交互 当然有

有没有一种简单的方法可以允许与位于另一个UIView下的UIView中的按钮进行交互?如果按钮顶部的UIView中没有实际对象

例如,目前我有一个UIVIEW(A),在顶部有一个对象,在屏幕的底部有一个对象,中间没有任何东西。这位于另一个UIVIEW的顶部,中间有按钮(B)。但是,我似乎不能与B.</P>中的按钮交互。 我可以看到B中的按钮-我已经将A的背景设置为clearColor-但是B中的按钮似乎没有收到触动,尽管事实上这些按钮上面没有来自A的对象

编辑-我仍然希望能够与俯视图中的对象交互


当然有一种简单的方法可以做到这一点?

您必须设置
upperView.userInteractionEnabled=NO,否则上方视图将截获触摸


此界面生成器版本是“视图属性”面板底部名为“已启用用户交互”的复选框。取消选中它,您就可以开始了。

我从未使用UI工具包构建过完整的用户界面,因此我对它没有太多经验。不过,我认为应该是这样的

每个UIView以及UIWindow都有一个属性
子视图
,它是一个包含所有子视图的NSArray

添加到视图的第一个子视图将接收索引0,下一个子视图将接收索引1,依此类推。您还可以将
addSubview:
替换为
insertSubview:atIndex:
insertSubview:oversubview:
以及可以确定子视图在层次结构中的位置的方法

因此,请检查您的代码,查看您首先将哪个视图添加到UIWindow中。这将是0,另一个将是1。
现在,要从一个子视图访问另一个子视图,请执行以下操作:

UIView * theOtherView = [[[self superview] subviews] objectAtIndex: 0];
// or using the properties syntax
UIView * theOtherView = [self.superview.subviews objectAtIndex:0];
让我知道这对你的案子是否有效


(下面是我以前的回答):

如果视图需要相互通信,则应通过控制器(即使用流行模型)进行通信

创建新视图时,可以确保它向控制器注册自身

因此,技术是确保您的视图注册到一个控制器(该控制器可以按名称或您喜欢的任何内容在字典或数组中存储它们)。您可以让控制器为您发送消息,也可以获取视图的引用并直接与其通信


如果您的视图没有返回控制器的链接(可能是这种情况),那么您可以使用和/或类方法获取对控制器的引用。

您可以在两个视图中截取触摸

俯视图:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Do code in the top view
   [bottomView touchesBegan:touches withEvent:event]; // And pass them on to bottomView
   // You have to implement the code for touchesBegan, touchesEnded, touchesCancelled in top/bottom view.
}

但这就是想法。

您应该为俯视图创建UIView子类,并覆盖以下方法:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // UIView will be "transparent" for touch events if we return NO
    return (point.y < MIDDLE_Y1 || point.y > MIDDLE_Y2);
}
-(BOOL)点内部:(CGPoint)点与事件:(UIEvent*)事件{
//如果我们返回否,UIView将对触摸事件“透明”
返回(点yMIDDLE|Y2);
}

您还可以查看hitTest:event:method。

有几种方法可以处理此问题。我最喜欢的方法是在一个视图中覆盖hitTest:withEvent:,这个视图是冲突视图的一个公共超级视图(可能是间接的)(听起来像是你把它们称为a和B)。例如,类似这样的东西(这里A和B是UIView指针,其中B是“隐藏”指针,通常被忽略):

您还可以按照gyim的建议修改
pointInside:withEvent:
方法。这可以让你通过有效地“戳一个洞”来达到基本相同的效果,至少是为了触摸

另一种方法是事件转发,这意味着覆盖
touchsbegind:withEvent:
和类似的方法(如
touchsmoved:withEvent:
等),将一些触摸发送到不同的对象。例如,在A中,您可以这样写:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self shouldForwardTouches:touches]) {
        [B touchesBegan:touches withEvent:event];
    }
    else {
        // Do whatever A does with touches.
    }
}
然而,这并不总是按照您期望的方式工作!主要的是,像UIButton这样的内置控件总是会忽略转发的触摸。因此,第一种方法更可靠

这里有一篇很好的博客文章详细解释了所有这些,还有一个小型的xcode项目演示了这些想法,可在以下位置获得:

我的解决方案如下:

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint pointInView = [self.toolkitController.toolbar convertPoint:point fromView:self];

    if ([self.toolkitController.toolbar pointInside:pointInView withEvent:event]) {
       self.userInteractionEnabled = YES;
    } else {
       self.userInteractionEnabled = NO;
    }

    return [super hitTest:point withEvent:event];
}

希望这有助于

自定义pointInside:withEvent:的实现看起来确实是一条不错的路,但处理硬编码坐标对我来说似乎很奇怪。因此,我最终使用CGRectContainsPoint()函数检查CGPoint是否位于按钮CGRect内:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return (CGRectContainsPoint(disclosureButton.frame, point));
}

我想我参加这个聚会有点晚了,但我要补充一个可能的解决方案:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView != self) return hitView;
    return [self superview];
}
如果使用此代码覆盖自定义UIView的标准hitTest函数,它将只忽略视图本身。该视图的任何子视图都将正常返回其点击,并且任何本应进入视图本身的点击都会传递到其superview


-Ash

我认为正确的方法是使用视图层次结构中内置的视图链。 对于推送到主视图上的子视图,不要使用通用UIView,而是使用子类UIView(或UIImageView等其变体之一)来生成MYView:UIView(或任何您想要的超类型,如UIImageView)。在YourView的实现中,实现touchesBegind方法。当触碰该视图时,将调用此方法。在该实现中,您只需要一个实例方法:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ;
{   // cannot handle this event. pass off to super
    [self.superview touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event]; }
这个ToucheSBegind是一个响应器api,所以您不需要在公共或私有接口中声明它;这是一个你必须知道的神奇api。此self.superview最终将向viewController发出请求。然后,在viewController中实现此触摸开始处理触摸

请注意
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ;
{   // cannot handle this event. pass off to super
    [self.superview touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event]; }
UIView * topView = [[TOPView alloc] initWithFrame:[self bounds]];
[self addSubview:topView];
[topView setUserInteractionEnabled:NO];
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // If one of our subviews wants it, return YES
    for (UIView *subview in self.subviews) {
        CGPoint pointInSubview = [subview convertPoint:point fromView:self];
        if ([subview pointInside:pointInSubview withEvent:event]) {
            return YES;
        }
    }
    // otherwise return NO, as if userInteractionEnabled were NO
    return NO;
}
@implementation PassThroughUIView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *v in self.subviews) {
        CGPoint localPoint = [v convertPoint:point fromView:self];
        if (v.alpha > 0.01 && ![v isHidden] && v.userInteractionEnabled && [v pointInside:localPoint withEvent:event])
            return YES;
    }
    return NO;
}

@end
 for(UIGestureRecognizer *recognizer in topView.gestureRecognizers)
 {
     recognizer.delegate=self;
     [bottomView addGestureRecognizer:recognizer];   
 }
 topView.abView.userInteractionEnabled=NO; 
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self) return nil;
    return hitView;
}
@interface ISView : UIView
@property(nonatomic, assign) BOOL onlyRespondToTouchesInSubviews;
@end

@implementation ISView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self && onlyRespondToTouchesInSubviews) return nil;
    return hitView;
}
@end
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    return !CGRectContainsPoint(buttonView.frame, point)
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for subview in subviews {
        if subview.frame.contains(point) {
            return true
        }
    }
    return false
}
let hitView = super.hitTest(point, with: event)
if hitView == self { return nil }
return hitView
extension UIColor {
    static func colorOfPoint(point:CGPoint, in view: UIView) -> UIColor {

        var pixel: [CUnsignedChar] = [0, 0, 0, 0]

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

        let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)

        context!.translateBy(x: -point.x, y: -point.y)

        view.layer.render(in: context!)

        let red: CGFloat   = CGFloat(pixel[0]) / 255.0
        let green: CGFloat = CGFloat(pixel[1]) / 255.0
        let blue: CGFloat  = CGFloat(pixel[2]) / 255.0
        let alpha: CGFloat = CGFloat(pixel[3]) / 255.0

        let color = UIColor(red:red, green: green, blue:blue, alpha:alpha)

        return color
    }
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard UIColor.colorOfPoint(point: point, in: self).cgColor.alpha > 0 else { return nil }
    return super.hitTest(point, with: event)
}