在子视图外触摸时删除子视图

时间:2014-05-14 03:42:11

标签: objective-c uitableview uiview uinavigationbar

我的情况比列出的其他情况复杂一点。

我有一个占据大部分屏幕的UITableView。 每一行都会弹出一个包含更多个人资料信息的子视图。再次单击屏幕时,此子视图将消失。这非常有效。

在导航栏中,我有一个显示小菜单的按钮。

- (IBAction)menuButtonClicked:(UIBarButtonItem *)sender {
    //If menuView exists and Menu button is clicked, remove it from view
    if (self.menuView) {
        self.tableView.userInteractionEnabled = true;
        [self.menuView removeFromSuperview];
        self.menuView = Nil;
    }
    //Menu View doesn't exist so create it
    else {
        // Create the Menu View and add it to the parent view
        self.menuView = [[[NSBundle mainBundle] loadNibNamed:@"MenuView" owner:self 
           options:nil] objectAtIndex:0];
        self.menuView.layer.cornerRadius = 20.0f;
        self.menuView.layer.borderWidth = 3.0f;
        self.menuView.layer.borderColor = [UIColor whiteColor].CGColor;
        self.menuView.frame = CGRectMake(0, 64, self.menuView.frame.size.width,
                                     self.menuView.frame.size.height);

        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] 
            initWithTarget:self action:@selector(singleTapGestureCaptured:)];
        [self.menuView addGestureRecognizer:singleTap];

        //Disable Selection of Profiles while Menu is showing
        self.tableView.userInteractionEnabled = false;

        //Add MenuView to View
        [self.view addSubview: self.menuView];
    }
}

//Removed Sub Views from View when tapped
-(void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture{
    if(self.profileView){
        [self.profileView removeFromSuperview];
        self.profileView = Nil;
    }
    if(self.menuView) {
        self.tableView.userInteractionEnabled = true;
        [self.menuView removeFromSuperview];
        self.menuView = Nil;
    }
}

现在,如果再次单击菜单按钮(在上面的代码中工作),但是当用户触摸菜单以及tableView或导航栏时,我想要忽略此菜单。如果显示菜单,我不希望tableView显示它的配置文件子视图(在上面的代码中工作),但只需删除menuView。如果我触摸tableView,我就无法取消menuView。

有人能指出我正确的方向吗?

3 个答案:

答案 0 :(得分:2)

制作一个新的透明叠加视图,大小覆盖整个屏幕。将menuView添加为叠加层的子视图,然后将叠加层添加为主窗口的子视图。在点击上放置一个点按手势识别器,点击时会将其解除。

如果菜单视图上的按钮不起作用,您可能需要在手势识别器上将cancelsTouchesInView设置为NO。

大概这个(请原谅错别字,我没有编译过这个):

- (void)showMenu
{
  self.overlay = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  overlay.backgroundColor = [UIColor clearColor];

  self.menuView = /* code to load menuView */;

  [overlay addSubview:self.menuView];

  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self 
                                                                        action:@selector(onSingleTap:)];
  tap.cancelsTouchesInView = NO;
  [overlay addGestureRecognizer:tap];

  [self.tableView.window addSubview:overlay];
}

- (void)handleSingleTap:(UITapGestureRecognizer *)sender
{
  [self.overlay removeFromSuperview];
}

您可能还想添加滑动手势识别器以同时关闭叠加层,因为有人可能会尝试滚动表格,期望菜单被解除。

答案 1 :(得分:0)

在尝试使用我自己的自定义NIB文件制作自己的自定义自顶向下滑动菜单时,我发现这可以通过许多技术实现。我想建议并分享一个非常相似但在背景上使用自定义按钮创建的不同解决方案。 我一直在环顾四周,但找不到答案。 这与点击识别器非常相似,除了一件事 - 点击识别器遍布布局(包括子视图),而使用自定义按钮层允许您与顶视图交互并在点击时从超视图中删除/删除它下层(当下层是背景按钮时)。我就这样做了:

  1. 您创建了布局
  2. 您将具有UIButtonTypeCustom类型的UIButton添加到布局
  3. 您将此布局设置在您希望响应该点击/点击
  4. 的视图上
  5. 您可以在该布局顶部添加菜单视图,并为菜单设置动画以显示

    - (void)showMenuViewWithBackgroundButtonOverlay
        {
            self.backgroundButton = ({
                UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
                button.frame = self.view.frame;
                [button addTarget:self action:@selector(toggleAppMenu) forControlEvents:UIControlEventTouchUpInside];
                button;
            });
    
            if (!self.menu) {
                self.menu = [self createMenu]; // <-- get your own custom menu UIView
            }
            if (!self.overlay) {
                self.overlay = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
                self.overlay.backgroundColor = [UIColor clearColor];
    
                [self.overlay addSubview:self.backgroundButton];
    
                [self.overlay addSubview:self.menu];
    
                [self.view addSubview:self.overlay];
            }
    
            [self toggleAppMenu];
        }
    
  6. toggleAppMenu:

    - (void)toggleAppMenu
    {
        CGRect nowFrame = [self.menu frame];
        CGRect toBeFrame = nowFrame;
        CGFloat navHeight = self.navigationController.navigationBar.frame.size.height;
        CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
    
        if (self.showingMenu) {
            toBeFrame.origin.y = toBeFrame.origin.y-nowFrame.size.height-navHeight-statusBarHeight;
            [UIView animateWithDuration:0.5 animations:^{
                [self.menu setFrame: toBeFrame];
            }completion:^(BOOL finished) {
                self.showingMenu = !self.showingMenu;
                [self.view endEditing:YES];
    
                [self.overlay removeFromSuperview];
                self.overlay = nil;
                NSLog(@"menu is NOT showing");
            }];
        }
        else{
            toBeFrame.origin.y = navHeight+statusBarHeight;
    
            [UIView animateWithDuration:0.5 animations:^{
                [self.menu setFrame: toBeFrame];
            }completion:^(BOOL finished) {
                self.showingMenu = !self.showingMenu;
                NSLog(@"menu is showing");
            }];
    
        }
    }
    

    我希望这会对某人有所帮助。

答案 2 :(得分:0)

适用于 Swift 5

我创建了自定义视图,并希望通过点击子视图外部来隐藏它。也许它可以帮助某人或任何人都可以提出更好的方法:)

// create tap for view
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(animateOut))
        self.addGestureRecognizer(tapGesture)
        
 // create tap for subview
        let tapGesture2 = UITapGestureRecognizer(target: self, action: nil)
        container.addGestureRecognizer(tapGesture2)