I have a question on how to add a tap gesture to a UITabBarController. As the UITabBarController already has tap gestures built-in (responding to the tapping of the tab bar items on the tab bar), while technically I can add my own gesture to the tabBarController, the tabBar loses its own native tap gesture. Below is what I am trying to do:
UIViewController *VC1 = ....;
UIViewController *VC2 = ....;
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects: VC1, VC2, nil];
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc]
initWithTarget:VC1
action:#selector(tap:)];
[tabBarController.view addGestureRecognizer:tapGR];
This correctly responds to the tapping method "tap: ", but the tabBarController loses its native tapping responses to the tap bar items. I tried to add the gesture to one of the view controllers in the tabBarController like this:
[VC1.view addGestureRecognizer:tapGR];
but then doing it this way the tapping gesture is not recognized at all, although the tabBar's native tap recognition of the tapping on the tab bar items is retained.
Does anyone has any suggestions on how to resolve this type of issues? I guess one way is to pick another gesture other than tapping to go with tabBarController, but I'd really rather not do that....
Much thanks for viewing!
I have to wonder what exactly you're trying to do with taps on a control that already handles taps. Do consider whether what you're doing is going to confuse your users.
But if you must, try setting cancelsTouchesInView to NO on the gesture recognizer. That should allow the touches to be passed on to the view in addition to being processed by your recognizer.
Related
A NSStatusItem has a NSMenu attached, and one of the buttons of the NSMenu opens a NSWindow. Whenever one of these buttons is clicked, the window opens as expected and works properly, but another display of the NSStatusItem is opened.
The NSStatusItem is a clock, so I can see that it is updating correctly. However, the cloned NSStatusItem doesn't have its own menu. If I push the button that makes the window more times, more cloned versions of the NSStatusItem pop up.
Everything works fine except for this.
That's not a whole lot of information to go off of, but there's nothing else I can think of that could potentially help you. I would be happy to provide more information or try something.
EDIT: Every time the button is clicked, awakeFromNib is somehow called, which is why another half-working NSStatusItem happens.
EDIT: Temporary workaround is to put the awakeFromNib method in a dispatch_once.
EDIT: Added method that is triggered when button is clicked, as suggested by #zpasternack
- (IBAction)preferences:(id)sender {
self.windowController = [[NSWindowController alloc] initWithWindowNibName:#"PreferencesWindow"];
[[self windowController] showWindow:self];
}
Is the NSStatusItem contained in the PreferencesWindow nib? That might explain it, since you're loading the nib each time the button is clicked.
Also, is there a reason you need to recreate that window each time the button is clicked? Maybe you could only do it the first time?
- (IBAction)preferences:(id)sender {
if( self.windowController == nil ) {
self.windowController = [[NSWindowController alloc] initWithWindowNibName:#"PreferencesWindow"];
}
[[self windowController] showWindow:self];
}
I have added a label with some text and links to an ScrollView,
when you tap on those links (in the label), a delegate method will call, displays a popover and show some related information.
but problem starts from here, I want when you tap on anywhere else except the links, the popover disappear.
if I add a UITapGestureRecognizer to ScrollView, the delegate method for links won't call.
what should I do to label handles the tap on links, and ScrollView Handles the other taps?
I did like that:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped)];
[self.scrollView addGestureRecognizer:tap];
- (void)tapped
{
if ([self.storyText.delegate respondsToSelector:#selector(attributedLabel:shouldFollowLink:)])
[self.storyText.delegate performSelector:#selector(attributedLabel:shouldFollowLink:) withObject:self.storyText];
}
In tapped method Im checking if Im tapping on a link, the delegate should be called, but Delegate wont call.
Am I missing someThing?
You can use custom UIButtons instead of labels or you can place custom UIButtons with clear background color over the links and give actions to this buttons.
Solved!
Solution:
first I create a custom class for my scrollView and subclassed that from UIScrollView.
Second I override
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
in my custom ScrollView class. in this method I called a method to dismiss the popover.
but important part is that in viewWillAppear method of the class which popover will appear, I passed self to custom scrollView class. because if I didn't that, the method for dismissing popover won't work (it needs an object of this class).
[self.scrollView initWithStoryViewController:self];
this images show in which scenario I had this problem:
In the apps that i have seen, info light buttons are all in the navigation bar and when touched, the transition to a new view is a horizontal flip. Is it okay if i make an application that does not have the info light button in the navigation bar and when touched, uses the push animation to transfer the user to a new view? If not, could someone tell me how to code for the horizontal flip because when i choose Modal and flip and connect to a view, nothing happens when pressed (but works if if i choose push instead of modal.
Thanks
You can do what ever you want. There is no guideline for what kind of button should cause what kind of view change.
Here's a couple of examples of how to change view controllers:
//if you are using xibs use this line
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"myXib" bundle:[NSBundle mainBundle]];
//if you are using storyboards use this line
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"myViewControllersID"];
[controller setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
//this sets the modal transition style
//to present the controller modally use this
[self presentViewController:controller animated:YES completion:nil];
//or if you are pushing to this controller using a navigation controller use this
[self.navigationController pushViewController:controller animated:YES];
I'm very new with iOS Development and I have just created one of my first apps, in my .xib file I have a UINavigationBar that I want to hide/show when a part of the screen is tapped by the user (like in the Photo app). I've found some snippets online but I don't know where and how to use those.
I'd appreciate a lot if somebody could give me detailed informations about how to do this.
Add this toggle method anywhere in your UIViewController. This hides on first tap and shows again in second tap.
- (void)toggleNavBar:(UITapGestureRecognizer *)gesture {
BOOL barsHidden = self.navigationController.navigationBar.hidden;
[self.navigationController setNavigationBarHidden:!barsHidden animated:YES];
}
If there is no navigation controller, link the navigation bar with an IBOutlet and replace with
- (void)toggleNavBar:(UITapGestureRecognizer *)gesture {
BOOL barsHidden = self.navBar.hidden;
self.navBar.hidden = !barsHidden;
}
Then add the following in the method -(void)viewDidLoad {}
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(toggleNavBar:)];
[self.view addGestureRecognizer:gesture];
[gesture release];
If the view where you are going to tap is a UIWebViewController, you have to add the protocol to the view controller and set it as delegate gesture.delegate = self; then add the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
This is needed because the UIWebViewController already implements its own gesture recognizers.
Ultimately, you want to send the -setHidden: message to your navigation bar. The easiest way to do this is to make an Outlet and an Action in your in your view controller. Then, in your .xib file, connect the navigation bar to the outlet and some button (even a large, full screen one) to the action.
Outlets and Actions are basic techniques used over and over in iOS
(and Mac) programming, so if you don't understand them, best go read
up on them now. Every beginning iOS/Mac programming book covers this
topic as does Apple's own Getting Started guide (pay particular
attention to the Configuring the View section).
Inside your action, send a message to the outlet like so:
-(void)myButtonAction:(id)sender{
[[self myNavigationBarOutlet] setHidden:YES];
}
This will hide the navigation bar whenever your button is tapped.
(This assumes you have a UINavigationBar in your .xib like you say. These directions will be different if you're working with a UINavigationController that manages its own UINavigationBar)
It seems as if this has been a reported bug already (http://openradar.appspot.com/9722231), but is there a way to get around it? Or is there an alternative to the NSPopover that can be used to create the same kind of interface?
Thanks in advance
Here's some code:
Popover creation
popover = [[NSPopover alloc] init];
popover.contentViewController = popover_controller;
popover.appearance = NSPopoverAppearanceMinimal;
popover.animates = YES;
popover.behavior = NSPopoverBehaviorTransient;
popover.delegate = self;
Displaying the Popover
[popover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
The sender is the NSStatusItem. The popover is displayed just fine, but if you try to click on the NSTextField, you are unable to edit the text or just gain focus in general.
So it turns out that this is a core OS bug and the only way around it was to use a custom NSWindow that looks like an NSPopover. I decided to use MAAttachedWindow.