I have view with a UITextView for comments on the bottom. Since its on the bottom of the page, whenever someone edits it, a method is called to shift the view of the page, so that you can still see the comment box. My problem is that the same method also gets called when user are editing UITextFields.
Here's what I have. First I declare a notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
Then the method itself
- (void)keyboardWillShow:(NSNotification *)notif{
...
}
My first thought was to add a condition, to check and see if the object was a TextView, and only then execute the code. But since I am not passing the object to the method, is there anyway to tell the method what type of object I am dealing with
Text fields and text views also send notifications. In the textFieldShouldBeginEditing and the textViewShouldBeginEditing implementations you could set a flag that you can read in your implementation of the keyboardWillShow method -- the keyboard notification is sent after the text field or text view notifications.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
self.sender = #"text field";
return YES;
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
self.sender = #"text view";
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
}
- (void)keyboardWillShow:(NSNotification *)notif{
NSLog(#"%#",self.sender);
}
Related
I am communicating between two classes with NSNotificationCenter. My problem is that although I tap a button once (and that button only fires off once) I am unintentionally producing increasing numbers of notifications from only one call to the NSNotificationCenter.
Here is a better explanation of the problem, with code:
My two classes are the mainView class and the Menu class.
When a view in the mainView class is tapped, it launches a view created and governed by the Menu class. This code is called when the mainView is initialized:
menu=[[MyMenu alloc] init];
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onTapped:)];
[tap setNumberOfTapsRequired:1];
[container addGestureRecognizer:tap];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onChangeItem:) name:#"ItemChange" object:nil];
This Gesture Recognizer fires off this method, also in the mainView class:
- (void) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(#"tap");
[menu displayMenu];
}
This is how the Menu class initializes:
- (MyMenu*) init {
self=[super init];
UICollectionViewFlowLayout * layout=[[UICollectionViewFlowLayout alloc] init];
menuView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 200, 200) collectionViewLayout:layout];
[menuView setDataSource:self];
[menuView setDelegate:self];
[menuView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cell"];
[menuView setAutoresizesSubviews:YES];
[menuView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
[menuView setBackgroundColor:[UIColor clearColor]];
[menuView setIndicatorStyle:UIScrollViewIndicatorStyleWhite];
return self;
}
And this is the displayMenu method inside the Menu class:
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
The Menu class also has a clearMenu method:
- (void) clearMenu {
[menuView removeFromSuperview];
}
This is the code for each cell in the UICollectionView, contained within my Menu class:
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
[cell setTag:indexPath.row];
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[cell addGestureRecognizer:tap];
NSLog(#"button tapped : %d",indexPath.row);
return cell;
}
This calls the onButtonTapped: method, also within my Menu class:
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:#"ItemChange" object:nil userInfo:#{#"selected":#(buttonTapped)}];
[self clearMenu];
}
This notification is picked up by my mainView class with this code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onChangeItem:) name:#"ItemChange" object:nil];
This calls the onChangeItem: method, inside my mainView class:
- (void) onChangeItem: (NSNotification*) notification {
NSLog(#"change item to %d",[[[notification userInfo] objectForKey:#"clock"] intValue]);
}
So that's the code.
OK, here's the problem: the first time the menu displays I get this in my log:
...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
And this is fine, this is what I expect. However second time around I get this:
...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
Third time around I get this:
...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
And so on. Each successive tap on a menu item doubles the amount of notification calls.
To begin with I thought I was adding multiple views, and thus resulting in multiple button taps, and therefore multiple notifications calls.
However as you can see from my logs, this is not the case. The buttons are only receiving 1 tap event - this is firing off only 1 notification - but receiving class gets sent multiple notifications.
Can anyone explain this to me?
Sorry for the lengthy post!
Well, I am assuming that [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onChangeItem:) name:#"ItemChange" object:nil]; are being added more than once.
I like to remove any potential observer before adding an observer, like so:
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"ItemChange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onChangeItem:) name:#"ItemChange" object:nil];
That way there will ever only be one observer callback.
Issue: I faced same problem, observer was calling twice, sometimes thrice.
Scenario
A user taps logout button
HomeViewController was dismissed and LoginViewController screen was presented
When user signed in again for second time
Observer was called twice (sometimes thrice)
The issue was [[NSNotificationCenter defaultCenter] removeObserver:self]; in dealloc method of my HomeViewController was not called at all, which actually removes an object from the notification center all together.
ℹ️ dealloc is an Objective-C selector that is sent by the
Objective-C runtime to an object when the object is no longer owned by
any part of the application.
Solution: Made your own method dispose and call it when user tap logout.
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
// ....
}
- (void)dispose {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)logoutTapped {
[self dispose];
// ....
}
I have a custom NSWindow class that has the following methods:
- (void)setupWindowForEvents{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowDidResignKey:) name:NSWindowDidResignMainNotification object:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:self];
}
-(void)windowDidResignKey:(NSNotification *)note {
NSLog(#"notification");
[self close];
}
I call [_window setupWindowForEvents]; but the windowDidResignKey never gets called.
This is how I call my NSWindow: when the status bar item is clicked I makeKeyAndOrderFront and the Window is displayed right beneath the status bar item, like this:
Any ideas why the I don't get any notification when the window loses focus? I've used both NSWindowDidResignMainNotification and NSWindowDidResignKeyNotification to see if any of these worked, but none is working.
You're probably not getting the notification because you actually are never key in the first place. Your window appears to be borderless, and borderless windows don't grab key window status by default.
In your window subclass, be sure to return YES on the following methods:
- (BOOL)canBecomeKeyWindow {
return YES;
}
- (BOOL)canBecomeMainWindow {
return YES;
}
I have a modal view created in a method (there is no reference in the mainview) and I want to do a dismissModalViewControllerAnimated automatically when my app enter in background. How can I do that ?
In the mainview's viewDidLoad, add observer to be notified when app goes to background.
- (void) viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(goToBackground)
name:UIApplicationWillResignActiveNotification object:nil];
}
Define the function goToBackground(). It will be called when the app goes to background
- (void) goToBackground
{
[self dismissModalViewControllerAnimated: NO]; // no need to animate
}
Don't forget to remove the observer
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
You can use a notification. Post a notification from the ApplicationDelegate's method applicationDidEnterBackground:. YOu can call the dismiss method from the modal controller, so add it as observer to the notification center.
When I try to scroll and edit the cells at the bottom of the UITableView, I can't manage to get my cells properly positioned above the keyboard. Actually keyboard hides half of the table view.
Also i created a custom cell class separately for my cells. So text fields delegates are available on that class only. i can't use them in my table biew's view controller
I have seen many answers talking about changing view sizes,etc... but none of them has worked nicely so far.
could anybody help me with this with a piece of code
An easier way to do this now (don't know how long this has been available): if you're overriding viewWillAppear, make sure to include at the top
[super viewWillAppear:animated];
I was all set to start listening to keyboard events and setting and removing constraints and just this one line eliminated all that other code.
You want to adjust the scrollView component of the UITableView. Set your view controller to respond to Keyboard notifications. Like this :
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Then create a keyboardWillShow: function and adjust the tableview by manipulating the tableView.scrollview.contentOffset (it might be tableView.contentOffset im not near xcode). Make sure you make a keyboardWillHide function to adjust it back to 0,0.
How can I interact with the button "hide keypad"
In IPad numeric pad.
I need to add validation for this button.
Or how I can switch off this button?
This is not the delegate method for the keyboard hide button .But I think You can solve this by adding the following code to you .m file
1.Add the following code to your viewWillAppear function
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardDidHideNotification
object:nil];
2.Add the following code to viewWillDisappear function
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
3.Declare function in .h file
-(void)keyboardWillHide:(NSNotification*)notify;
4.Define function in .m file
-(void)keyboardWillHide :(NSNotification*)notif
{
//Add the code for What you wish to do after the key board hide.
}
Use this to get the moment when the user hits that button
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
//your code here
return YES;
}