I've got the View-Controller with a button. I want the new view to be loaded over my View-Controller when the button is pressed. It'd not replace the existing view, I want it to be smaller than the screen and hide when I tap out of the small view.
How should it be implemented in code?
- (IBAction)button:(id)sender
{
UIView *view2=[[UIView alloc]initWithFrame:CGRectMake(0,0,200,200)];
[self.view addSubview:view2];
UITapGestureRecognizer *Tap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(Tapview)] autorelease];
[view2 addGestureRecognizer:Tap];
}
-(void)Tapview
{
[view2 removeFromSuperview];
}
Add Tap Gesture to self.view like this:
UITapGestureRecognizer *oneFinger =
[[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(oneFingerAction:)] autorelease];
// Set required taps and number of touches
[oneFinger setNumberOfTapsRequired:1];
[oneFinger setNumberOfTouchesRequired:1];
// Add the gesture to the view
[[self view] addGestureRecognizer:oneFinger];
Add one BOOL flag in .h file; in ViewDidLoad method add this:
flag = FALSE;
Now I assume u have UIView *smallView which be added on screen like this:
[self.view addSubView:smallView];
flag = TRUE;
smallView.center = self.view.centre;
Now when tapped on self.view tap gesture action called
- (void)oneFingerAction:(UITapGestureRecognizer*)sender
{
if(sender.view == self.view)
{
if(flag){
if(smallView)
{
[smallView removeFromSuperView];
}
}
}
}
Related
Here is the code that I am using for popup:
-(void)popup:(id)sender
{
//button action
UIView *popView=[[UIView alloc]initWithFrame:CGRectMake(Screen_Width-200,40, self.view.frame.size.width-130, self.view.frame.size.height/2-60)];
[popView setBackgroundColor:[UIColor redColor]];
popView.userInteractionEnabled = YES;
[self.view addSubview: popView];
}
You can do something like this in your viewDidLoad. So it's hidden bydefault.
UIView *popView=[[UIView alloc]initWithFrame:CGRectMake(Screen_Width-200,40, self.view.frame.size.width-130, self.view.frame.size.height/2-60)];
[popView setBackgroundColor:[UIColor redColor]];
popView.hidden = YES;
popView.userInteractionEnabled = YES;
[self.view addSubview: popView];
On your button click show it like,
popView.hidden = NO;
And take UITapGestureRecognizer on main View or root view and on touches call,
popView.hidden = YES;
Exaample of TapGestureRecognizer
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];
[self.view setUserInteractionEnabled:YES];
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
popView.hidden = YES;
}
Hope this will help :)
My situation is a little more complicated than the others listed.
I have a UITableView that takes up most of the screen.
Each row pops up a subview that contains more profile information. When the screen is clicked again this subview disappears. This works perfectly.
In the Navigation Bar I have a button that will display a small menu.
- (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;
}
}
Now I want to dismiss this menus if the menu button is clicked again (working in above code) but also when the user touches out of the menu and on the tableView or navbar. If the menu is displayed, I don't want the tableView to display it's profile subview (working in above code) but just remove the menuView. I can't get the menuView to go away if I touch the tableView.
Can anyone point me in the right direction?
Make a new transparent overlay view sized to cover the entire screen. Add your menuView as a subview of the overlay, then add the overlay as a subview of your main window. Put a tap gesture recognizer on the overlay that will dismiss it when tapped.
You may need to set cancelsTouchesInView to NO on your gesture recognizer if buttons on your menu view are not working.
Roughly this (please excuse typos, I haven't compiled this):
- (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];
}
You might also want to add a swipe gesture recognizer to also dismiss the overlay, as someone may attempt to scroll the table expecting the menu to be dismissed.
While trying to make my own custom topdown-slide menu using my own custom NIB file, I found that this can be achieved by many techniques. I would like to suggest and share a different solution which is very similar but is created with a custom button on the background.
I've been looking around but could not find answers mentioning this.
This is very similar to the tap recogniser except for one thing - tap recogniser spreads all over the layout (including subviews), while using a layer of custom button allows you to interact with the top view and dismiss/ remove it from superview when clicking on lower layer (when lower layer is the background button). This is how I did it:
You create the layout
You add a UIButton with type UIButtonTypeCustom to the layout
You frame this layout over the view you wish to be responsive to that tap/click
You add your menu view on top of that layout and animate your menu to appear
- (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];
}
And the 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");
}];
}
}
I hope this will be helpful for someone.
Works on Swift 5
I create custom view and I want it hide by tap outside subview. Maybe it can help for someone or anybody can suggest a better way :)
// 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)
I have a UIView where i added a UITapGestureRecognizer:
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
tapRecognizer.numberOfTapsRequired=1;
tapRecognizer.numberOfTouchesRequired=1;
[self.myView addGestureRecognizer:tapRecognizer];
I then add a UIToolBar with a button to the view:
UIToolbar *topBar = [[UIToolbar alloc ]initWithFrame:CGRectMake(0, 0, self.myView.frame.size.width, 44)];
topBar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *logout = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonItemStyleBordered target:self action:#selector(logout)];
[topBar setItems:#[logout] animated:NO];
I'm having an issue where I click on the logout button, and my tap recognier fires instead of my logout action. If I click and hold, then the logout action will fire (I'm guessing the tap recognizer is failing so lets the buttion action fire).
how can I not fire the gesture recognizer when the button is pressed?
Just had the same problem. Because I don't want to introduce container views (the UIToolbar should cover my existing view). With the help of Patrick.Ji's coarsely pointing I came up with this:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view.superview isKindOfClass:[UIToolbar class]]) {
return NO;
}
return YES;
}
Don't forget to set the delegate of the gesture to self
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *mainTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(mainTapGesture:)];
mainTapGestureRecognizer.delegate = self;
[self.view addGestureRecognizer:mainTapGestureRecognizer];
}
Check the view in your tap recognizer. If it is your logout button, let the touch fail to pass it up the chain via super.
Alternatively, make sure your toolbar is not a subview of your view. Instead, have a container view containing with your toolbar and your content view, and add the gesture recognizer to this content view.
implement this delegate method of UIGestureRecognizer (remember to set your tapRecognizer.delegate = self)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch {
if ([touch.view isKindOfClass:[UIBarButtonItem class]])
{
return NO;
}
return YES;
}
I have a button and I'm testing the taps on it, with one tap it change a background color, with two taps another color and with three taps another color again.
The code is:
- (IBAction) button
{
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnce:)];
UITapGestureRecognizer *tapTwice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTwice:)];
UITapGestureRecognizer *tapTrice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTrice:)];
tapOnce.numberOfTapsRequired = 1;
tapTwice.numberOfTapsRequired = 2;
tapTrice.numberOfTapsRequired = 3;
//stops tapOnce from overriding tapTwice
[tapOnce requireGestureRecognizerToFail:tapTwice];
[tapTwice requireGestureRecognizerToFail:tapTrice];
//then need to add the gesture recogniser to a view - this will be the view that recognises the gesture
[self.view addGestureRecognizer:tapOnce];
[self.view addGestureRecognizer:tapTwice];
[self.view addGestureRecognizer:tapTrice];
}
- (void)tapOnce:(UIGestureRecognizer *)gesture
{
self.view.backgroundColor = [UIColor redColor];
}
- (void)tapTwice:(UIGestureRecognizer *)gesture
{
self.view.backgroundColor = [UIColor blackColor];
}
- (void)tapTrice:(UIGestureRecognizer *)gesture
{
self.view.backgroundColor = [UIColor yellowColor];
}
The problem is that the first tap don't works, the other yes.
If I use this code without button it works perfectly.
Thanks.
If you want the colors to change on tap of button, you should add these gestures on button in viewDidLoad method or so rather than on the same button action. The above code will repeatedly add gestures on tap of the button to the self.view and not on button.
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnce:)];
UITapGestureRecognizer *tapTwice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTwice:)];
UITapGestureRecognizer *tapTrice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTrice:)];
tapOnce.numberOfTapsRequired = 1;
tapTwice.numberOfTapsRequired = 2;
tapTrice.numberOfTapsRequired = 3;
//stops tapOnce from overriding tapTwice
[tapOnce requireGestureRecognizerToFail:tapTwice];
[tapTwice requireGestureRecognizerToFail:tapTrice];
//then need to add the gesture recogniser to a view - this will be the view that recognises the gesture
[self.button addGestureRecognizer:tapOnce]; //remove the other button action which calls method `button`
[self.button addGestureRecognizer:tapTwice];
[self.button addGestureRecognizer:tapTrice];
}
Currently I'm facing a problem, I would like to perform action when the UIImageView on my UITableViewCell had been tapped.
Question: How could I do it? Could any one show me the code, or any tutorial?
Thanks in advance!
This is actually easier than you would think. You just need to make sure that you enable user interaction on the imageView, and you can add a tap gesture to it. This should be done when the cell is instantiated to avoid having multiple tap gestures added to the same image view. For example:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myTapMethod:)];
[self.imageView addGestureRecognizer:tap];
[self.imageView setUserInteractionEnabled:YES];
}
return self;
}
- (void)myTapMethod:(UITapGestureRecognizer *)tapGesture
{
UIImageView *imageView = (UIImageView *)tapGesture.view;
NSLog(#"%#", imageView);
}
Try this
//within cellForRowAtIndexPath (where customer table cell with imageview is created and reused)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleImageTap:)];
tap.cancelsTouchesInView = YES;
tap.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:tap];
// handle method
- (void) handleImageTap:(UIGestureRecognizer *)gestureRecognizer
{
RKLogDebug(#"imaged tab");
}
make sure u have....
imageView.userInteractionEnabled = YES;
you can use a customButton instead UIImageView
A tap gesture recogniser can be very memory hungry and can cause other things on the page to break. I would personally reconmend you create a custom table cell, insert a button into the custom cell frame and in the tableview code set the self.customtablecell.background.image to the image you want. This way you can assign the button an IBaction to make it push to whatever view you want.
Use ALActionBlocks to action in block
__weak ALViewController *wSelf = self;
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithBlock:^(UITapGestureRecognizer *weakGR) {
NSLog(#"pan %#", NSStringFromCGPoint([weakGR locationInView:wSelf.view]));
}];
[self.imageView addGestureRecognizer:gr];