在外面点击时移除视图

Posted

技术标签:

【中文标题】在外面点击时移除视图【英文标题】:Remove view when tapped outside 【发布时间】:2015-08-21 23:55:08 【问题描述】:

我有一个 UIView,当点击按钮时我会出现,我基本上将它用作自定义警报视图。现在,当用户在我添加到主视图的自定义 UIView 之外点击时,我想隐藏 cusomt 视图,我可以使用 customView.hidden = YES; 轻松做到这一点,但是如何检查视图之外的点击?

感谢您的帮助

【问题讨论】:

【参考方案1】:

有两种方法

第一种方法

您可以为自定义视图设置标签:

customview.tag=99;

然后在您的视图控制器中,使用 touchesBegan:withEvent: 委托

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    UITouch *touch = [touches anyObject];

    if(touch.view.tag!=99)
        customview.hidden=YES;
    

第二种方法

更有可能的是,每次您想要弹出自定义视图时,它后面都会有一个覆盖层,它会填满您的屏幕(例如,alpha ~0.4 的黑色视图)。在这些情况下,您可以向其添加UITapGestureRecognizer,并在每次您希望自定义视图显示时将其添加到您的视图中。这是一个例子:

UIView *overlay;

-(void)addOverlay
        overlay = [[UIView alloc] initWithFrame:CGRectMake(0,  0,self.view.frame.size.width, self.view.frame.size.height)];
    [overlay setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]];

    UITapGestureRecognizer *overlayTap =
    [[UITapGestureRecognizer alloc] initWithTarget:self
                                        action:@selector(onOverlayTapped)];

    [overlay addGestureRecognizer:overlayTap];
    [self.view addSubview:overlay];


- (void)onOverlayTapped

    NSLog(@"Overlay tapped");
    //Animate the hide effect, you can also simply use customview.hidden=YES;
    [UIView animateWithDuration:0.2f animations:^
        overlay.alpha=0;
        customview.alpha=0;
    completion:^(BOOL finished) 
        [overlay removeFromSuperview];
    ];

【讨论】:

我会建议第一种方法,而不是使用不必要的控件 (UITapGestureRecognizer)。最重要的是“更少的代码,更稳定的应用程序” 在这个答案中,第一种方法适用于我的项目,我将分享它的快速版本【参考方案2】:

就像在 FlySoFast 的答案中一样,我尝试了第一种方法,它很有效,我只是分享了它的 swift 版本。您可以将其标记为您的自定义视图并检查该视图是否触摸,因此我们实现了我猜的解决方案。在下面我将自定义视图的标记值分配给 900。

customview.tag = 900

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
    let touch = touches.first!
    if touch.view?.tag != 900 
        resetMenu()
    


希望这个回答对你有帮助

【讨论】:

【参考方案3】:

当您呈现自定义警报视图时,将该自定义警报视图添加到另一个全屏视图中,通过设置其backgroundColor 清除该视图以使该视图清晰。在主视图中添加全屏视图,并在全屏不可见视图中添加tapGesture,当它被点击时删除此视图。

但是,如果您这样做,即使您触摸自定义警报视图,它也会关闭视图,您需要设置 tapGesture 的委托并实现此方法

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

    if ([touch.view isDescendantOfView:self.customAlertView])
    
        return NO;
    
    return YES;

【讨论】:

【参考方案4】:

在 Swift 中使用函数 pointInside:

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool 

    if let view = customView 
        //if UIView is open open
        let newPoint = self.convertPoint(point, toView: view)
        let pointIsInsideGenius = view.pointInside(newPoint, withEvent: event)
        // tapping inside of UIView
        if pointIsInsideGenius 
            return true
         else 
        // if tapped outside then remove UIView
                view.removeFromSuperview()
                view = nil
            
        
    

    return false

【讨论】:

【参考方案5】:

你可以使用这个库:https://github.com/huynguyencong/EzPopup

初始化一个PopUpController你想在点击外部时关闭它的视图

let popup = PopupViewController(contentView: viewNeedToRemoveWhenTapOutside, position: .bottomLeft(position))
present(popup, animated: true, completion: nil)

【讨论】:

【参考方案6】:

顺便说一句,你可以做这个。主要技巧是一个将全屏包裹在自定义视图后面的按钮。当您单击按钮时,您只需关闭您的自定义视图。这是完整的代码。

这是完整的自定义 uiview 类

import Foundation
import UIKit
class CustomAlartView: UIView 
    
    static let instance = CustomAlartView()
    
    @IBOutlet var parentView: UIView!
    @IBOutlet weak var mainView: UIView!
    @IBOutlet weak var userInput: UITextField!
    override init(frame: CGRect) 
        super.init(frame: frame)
        Bundle.main.loadNibNamed("CustomAlartView", owner: self, options: nil)
        setupView()
      
      
      //initWithCode to init view from xib or storyboard
      required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
//        setupView()
      
    @IBAction func tappedCancel(_ sender: Any) 
        parentView.removeFromSuperview()
    
    
    @IBAction func tappedOk(_ sender: Any) 
        if userInput.text == "" 
            print("\(userInput.text)")
        
        else
            parentView.removeFromSuperview()
        
    
    @IBAction func tappedOutside(_ sender: Any) 
        print("click outside")
        parentView.removeFromSuperview()
    
    //common func to init our view
      private func setupView() 
        parentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        parentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        
        mainView.layer.shadowColor = UIColor.gray.cgColor
        mainView.layer.shadowOpacity = 1
        mainView.layer.shadowOffset = CGSize(width: 10, height: 10)
        mainView.layer.shadowRadius = 10
        mainView.layer.cornerRadius = 15
        mainView.layer.masksToBounds = true
      
    
    enum alartType 
        case success
        case failed
    
    func showAlart()  
        UIApplication.shared.keyWindow?.addSubview(parentView)
    
    

【讨论】:

以上是关于在外面点击时移除视图的主要内容,如果未能解决你的问题,请参考以下文章

单击时移除 QPushButton 周围的方格边框

在核心动画中移除或隐藏图层时移除不透明度和时间间隔

在外面点击时如何关闭我的幻灯片菜单?

text jquery - 在外面点击时隐藏

javascript Boostrap popovers隐藏在外面和其他popovers的点击

遍历 NodeList 时移除 DOM 节点