Purpose: I am attempting to toggle the "Save" UIBarButtonItem with the "Hide Keyboard" UIBarButtonItem whenever the Keyboard appears (and then do the opposite when the "Hide Keyboard" button is clicked).
So far I have created two UIBarButtonItems and connected them both to Interface Builder.
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *hideKeyButton;
This is the code I have setup so far in my main:
- (void)keyboardDidShow:(NSNotification *)aNotification {
// Show HideKey Button
// Hide Save Button
}
- (void)keyboardWillHide:(NSNotification *)aNotification {
// Show Save Button
// Hide HideKey Button
}
On Interface Builder, the Save button is present by default. Programatically, how do I show the HideKey button and Hide the Save button? Thanks.
There are two parts to make this work.
First, you need to register for the notifications, what you can do is, in your viewDidLoad, add the following:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
Secondly, in your event handlers, simply set the buttons:
- (void)keyboardDidShow:(NSNotification *)aNotification {
self.navigationItem.rightBarButtonItem = hideKeyButton;
}
- (void)keyboardWillHide:(NSNotification *)aNotification {
self.navigationItem.rightBarButtonItem = saveButton;
}
Instead of using IB for this task, I would do it programmatically.
Something like this:
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:#selector(saveButtonPressed:)];
[self.navigationItem setRightBarButtonItem:saveButton];
And in a similar fashion to create and set the HideKey button.
Then, of course you may want to cache the UIBarButtonItems, setting lazy #properties for them.
Related
This is HomeView
enter image description here
When Someone tapped in 'Banking' button . Action will load BaseviewController .
This is the button action.
HomeViewController.m
BaseViewController *clickbutton = [[BaseViewController alloc] initWithNibName:#"BaseViewController" bundle:nil] ;
[self presentViewController:clickbutton animated:YES completion:nil];
This is BaseView
enter image description here
There is a scrollbar which will load every view . The scrollbar
background is Green . And change the background in next here is the
problem .
BaseViewController.m
-(void)ViewDidLoad{
PriorityViewController *obj ;
UINavigationController *nav;
obj = [[ PriorityViewController alloc] initWithNibName:#"PriorityViewController" bundle:nil] ;
nav = [[UINavigationController alloc] initWithRootViewController:obj];
nav.view.frame = rect;
[self.view addSubview:self.nav.view];
}
When tapped 'Service Request' .
OtherBankTransferViewController *obj;
obj = [[OtherBankTransferViewController alloc]initWithNibName:#"OtherBankTransferViewController" bundle:nil];
[self.navigationController pushViewController:obj animated:YES ];
This will load same as like second image I uploaded here .
I just want to change my background color of the scrollbar
I want to change scrollbar into black color .
I have no idea . If someone explain me !
Thanks in advance .
APPROACH 1:
Instead of initialising scrollBar in each ViewController, why not alloc init it in BaseView Controller and pass instance of it to all View Controller.
Since now all ViewControllers will have same instance it will be easy to change background of the scrollBar.
APPROACH 2:
You can post notifications whenever you want to change the scrollBar color,
add observer for the notification you are posting and with the notification you can pass the color you want to be set for all scrollBar.
Posting Notification when you want to change color
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[UIColor blackColor] forKey:#"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"TestNotification" object:nil userInfo:userInfo];
Adding Observer in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
Method to handle received Notification
- (void) receiveTestNotification:(NSNotification *) notification{
NSDictionary *userInfo = notification.userInfo;
UIColor *backGroundColor = [userInfo objectForKey:#"someKey"];
// assign this color to your scrollBar in each ViewController
}
REMOVING OBSERVER in viewDidUnload
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"TestNotification" object:nil];
I have main viewcontroller that opens via popover segue other view controller with buttons.
On button click what I wish to happen is function from first viewcontroller fire and the popover will close. How do I do so properly?
On settings button click the popover open. Then when user click Manual Content Update the the view will close and start function on Projects Main viewController.
You can use NSNotificationCenter.
In your main UIViewController add:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivePopoverNotification:)
name:#"PopoverNotification"
object:nil];
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) receivePopoverNotification:(NSNotification *) notification
{
[self.popover dismissPopoverAnimated: YES];
self.popover = nil;
}
In your UIPopoverController add:
-(IBAction) pressButton: (id) sender {
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PopoverNotification"
object:nil];
}
TL;DR Update: Basically what I need is to delay my code until iOS finishes its "app startup" animation.
I would like to animate content of a navigation bar when my app becomes active. In my controller, I'm subscribed to UIApplicationDidBecomeActiveNotification and use setRightBarButtonItem:animated: to perform the change.
The problem is that the change is not animated.
I did some experimentation and discovered that if I wait a little ([NSThread sleepForTimeInterval:.3]), it's animating without any issues.
Here is a simple view controller demonstrating the problem:
#interface TESTViewController ()
#property (strong, nonatomic) IBOutlet UINavigationBar *navigationBar;
#end
#implementation TESTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UINavigationItem *item = [UINavigationItem new];
UIBarButtonItem *oldItem = [[UIBarButtonItem alloc] initWithTitle:#"Old" style:UIBarButtonItemStyleBordered target:nil action:NULL];
[item setRightBarButtonItem:oldItem];
[[self navigationBar] setItems:#[item] animated:NO];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidBecomeActiveNotificationAction:) name:UIApplicationDidBecomeActiveNotification object:nil];
}
- (void)applicationDidBecomeActiveNotificationAction:(NSNotification *)notification
{
// [NSThread sleepForTimeInterval:.3];
UIBarButtonItem *newItem = [[UIBarButtonItem alloc] initWithTitle:#"New" style:UIBarButtonItemStyleBordered target:nil action:NULL];
[[[self navigationBar] items][0] setRightBarButtonItem:newItem animated:YES];
}
#end
I'd like find a better solution than blocking the thread or performing the change after a fixed delay.
Simply use dispatch_after on the main queue instead of calling
+[NSThread sleepForTimeInterval:] class method.
Pass your animation as a block and it should work perfectly.
When posting notifications, I don't use your methods.
I use:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(changeButton) name:#"changeButton" object:nil];
on the receiving end.
And on the posting end, I call
[[NSNotificationCenter defaultCenter] postNotificationName:#"changeButton" object:nil];
Try moving your code to the method:
-(void)changeButton{
UIBarButtonItem *newItem = [[UIBarButtonItem alloc] initWithTitle:#"New" style:UIBarButtonItemStyleBordered target:nil action:NULL];
[[[self navigationBar] items][0] setRightBarButtonItem:newItem animated:YES];
}
Hope this helps!
Have you tried to performSelectorAfterDelay?
Try something like this:
- (void)applicationDidBecomeActiveNotificationAction:(NSNotification *)notification{
[self performSelector:#selector(yourAnimationAction) withObject:nil afterDelay:1];
}
- (void)yourAnimationAction{
//Set your NavAnimation here
[self.navigationItem setRightBarButtonItem:theItem animated:TRUE];
}
Just change the Delay to fit your apps wakeup delay... maybe this will take the effect?
Try by moving
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidBecomeActiveNotificationAction:) name:UIApplicationDidBecomeActiveNotification object:nil]; to viewDidLoad: method. I think object is not registered for "UIApplicationDidBecomeActiveNotification" while it is fired.
Just call viewDidAppear: manually from within your applicationDidBecomeActiveNotificationAction: method. Place your animation code in the viewDidAppear: method. Hope this helps.
I use a UITableView for a user/password login control. Right now it's the only control on the view, along with a login button. When i click inside, the text edit content becomes active, the keyboard pops up and I can type. however there is no way to stop the editing. I'd like to click outside on the white area of my UIView so that the focus is taken away from the text editors inside my UITableVIew and the keyboard becomes invisible again.
How do I do that?
You can add button which alpha channel is equil zero. There is behind your login and password field. Set action to this button in the following way:
-(void)hideKeyboard:(id)sender
{
[self.username resignFirstResponder];
[self.password resignFirstResponder];
}
In viewDidLoad make your view controller listen to keyboard notifications and create a tap recognizer which will receive all events outside of your tableView:
- (void)viewDidLoad
{
[super viewDidLoad];
...
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name:
UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name:
UIKeyboardWillHideNotification object:nil];
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard:)];
...
}
Then in the notification methods for the keyboard add and remove the gesture recognizer from your view.
//add gesture recognizer when keyboard appears
-(void)keyboardWillShow:(NSNotification *) note {
[self.view addGestureRecognizer:tapRecognizer];
}
//remove it when keyboard disappears
-(void)keyboardWillHide:(NSNotification *) note
{
[self.view removeGestureRecognizer:tapRecognizer];
}
In the action method of your gesture recognizer you resign all first responders to dismiss the keyboard:
-(IBAction)dismissKeyboard:(id)sender
{
//this removes ALL firstResponder from view
[self.view endEditing:TRUE];
}
Don't forget to end listening to the keyboard notifications at some point:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Add a Single Tap GestureRecognizer and resign the keyboard in the called function
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(resignKeyBoard)];
[tap setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:tap];
I have a UITableViewController that launches a UIViewController and I would like to trap whenever the back button is pressed in the child controller, which is the class that derives from 'UIViewController'. I can change the Back Button title but setting the target & action values when setting the backBarButtonItem seems to get ignored. What's a way to receiving some kind of notification that the Back button was tapped?
- (void)showDetailView
{
// How I'm creating & showing the detail controller
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyDetailView" bundle:nil];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Pages"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(handleBack:)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:controller animated:animated];
[controller release];
}
- (void)handleBack:(id)sender
{
// not reaching here
NSLog(#"handleBack event reached");
}
You can implement the viewWillDisappear method of UIViewController. This gets called when your controller is about to go away (either because another one was pushed onto the navigation controller stack, or because the 'back' button was pressed).
To determine whether the view is disappearing because of the back button being pressed, you can use a custom flag that you set wherever you push a new controller onto the navigation controller, like shown below
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (viewPushed) {
viewPushed = NO; // Flag indicates that view disappeared because we pushed another controller onto the navigation controller, we acknowledge it here
} else {
// Here, you know that back button was pressed
}
}
And wherever you push a new view controller, you would have to remember to also set that flag...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
viewPushed = YES;
[self.navigationController pushViewController:myNewController animated:YES];
...
}
It has been a while since this was asked, but I just tried to do this myself. I used a solution similar to Zoran's, however instead of using a flag I did this:
- (void)viewWillDisappear: (BOOL)animated
{
[super viewWillDisappear: animated];
if (![[self.navigationController viewControllers] containsObject: self])
{
// the view has been removed from the navigation stack, back is probably the cause
// this will be slow with a large stack however.
}
}
I think it bypasses the issues with flags and IMO is cleaner, however not as efficient (if there are lots of items on the navigation controller).
In my opinion the best solution.
- (void)didMoveToParentViewController:(UIViewController *)parent
{
if (![parent isEqual:self.parentViewController]) {
NSLog(#"Back pressed");
}
}
But it only works with iOS5+
I use this code:
- (void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound)
{
// your view controller already out of the stack, it meens user pressed Back button
}
}
But this is not actual when user presses tab bar button and pops to root view controller at one step. For this situation use this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(viewControllerChange:)
name:#"UINavigationControllerWillShowViewControllerNotification"
object:self.navigationController];
- (void) viewControllerChange:(NSNotification*)notification {
NSDictionary* userInfo = [notification userInfo];
if ([[userInfo objectForKey:#"UINavigationControllerNextVisibleViewController"] isKindOfClass:[<YourRootControllerClass> class]])
{
// do your staff here
}
}
Don't forget then:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"UINavigationControllerWillShowViewControllerNotification"
object:self.navigationController];
You can make your own button and place it as the leftBarButtonItem. Then have it call your method where you can do whatever, and call [self.navigationController popViewController... yourself
{
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(handleBack:)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];
[self filldata];
[super viewDidLoad];
}
just replace backBarButtonItem with leftBarButtonItem
Simply use viewDidDisappear instead. It will be perfectly called in any scenario.
We are basing your lifecycle management on viewDidAppear and viewDidDisappear. If you know Android: the both are comparable to onResume and onPause methods. But there is a difference when it comes to locking the screen or pressing the homebutton on iOS.