spen123
spen123

Reputation: 3524

Remove view when tapped outside

I have a UIView, that I have appear when a button is tapped, I am using it as a custom alert view essentially. Now when the user taps outside the custom UIView that I added to the main view, I want to hide the cusomt view, I can easily do this with customView.hidden = YES; but how can I check for the tap outside the view?

Thanks for the help

Upvotes: 7

Views: 8849

Answers (6)

FlySoFast
FlySoFast

Reputation: 1922

There are 2 approaches

First approach

You can set a tag for your custom view:

customview.tag=99;

An then in your viewcontroller, use the touchesBegan:withEvent: delegate

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

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

Second approach

It's more likely that every time you want to popup a custom view, there's an overlay behind it, which will fill your screen (e.g. a black view with alpha ~0.4). In these cases, you can add an UITapGestureRecognizer to it, and add it to your view every time you want your custom view to show up. Here's an example:

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];
    }];
}

Upvotes: 7

Md. Shofiulla
Md. Shofiulla

Reputation: 2305

You can make this by the way. The main tricks are a button that wraps the full screen behind your custom view. When you click on the button you simply dismiss your custom view. Here is the complete code.

design preview

Here is the complete custom uiview class

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)
    }
    
}

Upvotes: 0

huynguyen
huynguyen

Reputation: 7760

You can use this library: https://github.com/huynguyencong/EzPopup

Init a PopUpController the view that you want to dismiss it when tap outside

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

Upvotes: 0

Esat kemal Ekren
Esat kemal Ekren

Reputation: 556

Like in the answer of FlySoFast, I tried first approach and it worked I just shared to swift version of it. You can tag it of your custom view and the check the that view touched or not so we achieved our solution I guess.In the below I assign tag value of my custom view to 900.

customview.tag = 900

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

}

I hope this answer will help to you

Upvotes: 2

birdy
birdy

Reputation: 953

with using function pointInside in Swift:

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
}

Upvotes: 1

Adnan Aftab
Adnan Aftab

Reputation: 14477

When you presenting custom alert view, add that custom alert view in to another full screen view, make that view clear by setting its backgroundColor clear. Add full screen view in main view, and add tapGesture in fullScreen invisible view, when ever it gets tap remove this view.

But if you will do this it will dismiss view even when you touch custom alert view for that you need to set delegate of tapGesture and implement this method

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isDescendantOfView:self.customAlertView])
    {
        return NO;
    }
    return YES;
}

Upvotes: 1

Related Questions