My code:
NSDictionary *dict = #{#"1": #"_infoView3",
#"2": [NSNumber numberWithFloat:_showSelectionView.frame.size.height]
};
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:#"UIKeyboardWillShowNotification"
object:dict];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:#"UIKeyboardDidHideNotification"
object:dict];
and :
- (void) keyboardWillShow:(NSNotification *)note {
NSDictionary *userInfo = [note userInfo];
CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// move the view up by 30 pts
CGRect frame = self.view.frame;
frame.origin.y = -kbSize.height;
[UIView animateWithDuration:0.3 animations:^{
self.view.frame = frame;
}];
}
- (void) keyboardDidHide:(NSNotification *)note {
// move the view back to the origin
CGRect frame = self.view.frame;
frame.origin.y = 0;
[UIView animateWithDuration:0.3 animations:^{
self.view.frame = frame;
}];
}
But those two methods is not working when the keyboard is showing up or hiding.
And those two methods is working if I pass object nil, instead dict.
I don't know where is the problem, please help me , Thank you.
As I can see you are trying to post object at observer side. It is quite opposite, see the example below.
Receiver class
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"myNotification"
object:nil];
}
- (void)receiveNotification:(NSNotification *)notification
{
if ([[notification name] isEqualToString:#"myNotification"]) {
NSDictionary *myDictionary = (NSDictionary *)notification.object;
//doSomething here.
}
}
Sender Class
- (void)sendNotification {
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification" object:YOUR_DICTIONARY];
}
That's because the object parameter is designed to specify the particular object to observe, not for passing arbitrary data to the called selector.
From the reference:
notificationSender
The object whose notifications the observer wants
to receive; that is, only notifications sent by this sender are
delivered to the observer.
If you pass nil, the notification center doesn’t use a notification’s
sender to decide whether to deliver it to the observer.
Related
I am having trouble while i am creating a messaging app, When keyboard is opened i am not sure about total size and frame for Keyboard (dictionary area is opened or not).
I want to get total size and frame in
textFieldShouldBeginEditing
delegate.
You should use the UIKeyboardWillChangeFrameNotification . Also make sure to convert the CGRect into the proper view, for landscape use.
Set NSNotificationCenter in your textFieldShouldBeginEditing
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
and write this method.
- (void)keyboardWillChange:(NSNotification *)notification {
CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil]; //this is it!
}
In Swift 4
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(_noti:) ), name: NSNotification.Name.UIKeyboardWillChangeFrame , object: nil)
KeyboardWillChange Method
#objc func keyboardWillChange(_noti:NSNotification)
{
let keyBoard = _noti.userInfo
let keyBoardValue = keyBoard![UIKeyboardFrameEndUserInfoKey]
let fram = keyBoardValue as? CGRect // this is frame
}
Register for UIKeyboardWillShowNotification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
and in the selector get the keyboard frame:
- (void)keyboardWillShow:(NSNotification *)iNotification {
NSDictionary *userInfo = [iNotification userInfo];
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
}
I have faced this problem and solved by using notification observer on keyboard.
//set observer in textFieldShouldBeginEditing like
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myNotificationMethod:) name:UIKeyboardWillChangeFrameNotification object:nil];
return YES;
}
// method implementation
- (void)myNotificationMethod:(NSNotification*)notification
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
NSLog(#"%#",keyboardFrameBegin);
NSLog(#"%f",keyboardFrameBeginRect.size.height);
}
//remove observer
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
[[NSNotificationCenter defaultCenter ]removeObserver:self];
return YES;
}
I am working on a chat app wherein I have a textview (not textfield) and when I click on it, the keyboard should show and everything should move up.
Till now, I have managed to shift the frame of the table view and textview up and show the keyboard using the below code.
- (void)keyboardWasShown:(NSNotification *)notification {
NSDictionary* info = [notification userInfo];
keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGPoint contentViewOrigin = self.contentView.frame.origin;
CGFloat contentViewHeight = self.contentView.frame.size.height;
CGRect visibleRect = self.view.frame;
visibleRect.size.height -= keyboardSize.height;
BOOL up = CGRectContainsPoint(visibleRect, contentViewOrigin);
if (!up){
self.tableView.frame = CGRectMake(self.tableView.frame.origin.x,self.tableView.frame.origin.y,self.tableView.frame.size.width,280.0f);
self.contentView.frame = CGRectOffset(self.contentView.frame, 0, 0 - keyboardSize.height);
if([self.tableView numberOfRowsInSection:0]!=0)
{
NSIndexPath* ip = [NSIndexPath indexPathForRow:[self.tableView numberOfRowsInSection:0]-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionBottom animated:UITableViewRowAnimationLeft];
}
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification {
self.contentView.frame = originalContentView;
self.tableView.frame = originalTable;
}
- (void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)deregisterFromKeyboardNotifications {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
But when I saw how whatsapp does it, mine looked like a hack. Whatsapp's keyboard moves up together with all the elements while mine works like this: First the keyboard is shown, a notification is sent to the app, notification is received, the code calculates the height of keyboard and moves up the elements according to the height.
I have searched and found the solution that I have implemented.
Can someone help??
I use this trick a lot in my apps. You want to listen to UIKeyboardWillShowNotification and UIKeyboardWillHideNotification.
The best way to handle animation in my opinion is using autolayout. When you call [self.view layoutIfNeeded]; your views will move along with the keyboard animation. No animation block needed.
I've set up a simple project for anyone to try and see how it works!
- (void)addKeyboardNotificationsObserver {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)handleKeyboardWillShow:(NSNotification *)paramNotification
{
NSDictionary* info = [paramNotification userInfo];
//when switching languages keyboard might change its height (emoji keyboard is higher than most keyboards).
//You can get both sizes of the previous keyboard and the new one from info dictionary.
// size of the keyb that is about to disappear
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// size of the keyb that is about to appear
CGSize kbSizeNew = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
//make adjustments to constraints here...
//and here where's magick happen!
[self.view layoutIfNeeded];
}
- (void)handleKeyboardWillHide:(NSNotification *)paramNotification
{
//adjust constraints
[self.view layoutIfNeeded];
}
You can use UIKeyboardWillShowNotification and UIKeyboardWillHideNotification
Try TPKeyboardAvoidingScrollView from here: https://github.com/michaeltyson/TPKeyboardAvoiding (my choice)
In the UIViewController I add itself as observer:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
......
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
if (textField1.isFirstResponder) {
NSLog(#"I am here1");
}
if (textField2.isFirstResponder) {
NSLog(#"I am here2");
}
........
}
I also create five UITextField in the controller. My problem is how to know which textField is called. I try the method to find out whose "isFirstResponder" have change , but it is not working.
erm... why don't you use -textFieldDidBeginEditing: of UITextFieldDelegate
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(#"%#",textField);
}
Use the tag property!! When you create your Textfield set their tags (to some textfield-specific number), and when you get the notification, simply check which tag they have!
Try UIKeyboardDidShowNotification instead of UIKeyboardWillShowNotification.
This question already has answers here:
Making a UITableView scroll when text field is selected
(45 answers)
Closed 9 years ago.
I have an application with a UITableview and a UITextView, so sometimes the keyboard is up. Whenever the keyboard is up, I can't access the bottom 3-4 table cells because they are always stuck behind the keyboard. How can I make the UITableView only take up the space above the keyboard while the keyboard is displayed?
I normally use https://github.com/michaeltyson/TPKeyboardAvoiding
Which will automatically solve your normal problem
But if you want to do some coding manually
Use table views setContentOffset or scrollToRowAtIndexPath
CGPoint scrollPt = CGPointMake(textFieldRect.origin.x, textFieldRect.origin.y);
[_tableView setContentOffset:scrollPt animated:YES];
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
I've had the same problem, and here is my solution. Hope it helps.
- (void) keyboardWillShow: (NSNotification*) aNotification
{
[UIView animateWithDuration: [self keyboardAnimationDurationForNotification: aNotification] animations:^{
CGSize kbSize = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
//change the frame of your talbleiview via kbsize.height
} completion:^(BOOL finished) {
}];
}
- (void) keyboardDidShow: (NSNotification*) aNotification
{
[UIView animateWithDuration: [self keyboardAnimationDurationForNotification: aNotification] animations:^{
CGSize kbSize = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
//change the frame of your talbleiview via kbsize.height
} completion:^(BOOL finished) {
}];
}
- (void) keyboardWillDisappear: (NSNotification*) aNotification
{
[UIView animateWithDuration: [self keyboardAnimationDurationForNotification: aNotification] animations:^{
//restore your tableview
} completion:^(BOOL finished) {
}];
}
- (NSTimeInterval) keyboardAnimationDurationForNotification:(NSNotification*)notification
{
NSDictionary* info = [notification userInfo];
NSValue* value = [info objectForKey: UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 0;
[value getValue: &duration];
return duration;
}
Add and remove event listeners.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(keyboardWillShow:)
name: UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(keyboardDidShow:)
name: UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(keyboardWillDisappear:)
name: UIKeyboardWillHideNotification object:nil];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardWillShowNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardDidShowNotification object: nil];
[[NSNotificationCenter defaultCenter] removeObserver: self name: UIKeyboardWillHideNotification object: nil];
}
Methion that multi events will be received during one keyboard animation.
Try this:
CGRect frame = [tableViewer frame]; //assuming tableViewer is your tableview
frame.size.height -= 200; //200 may be a bit off, should be height of keyboard
[tableViewer setFrame:frame];
And the same thing but change -= to += for when the keyboard disappears.
I need to scroll up my scrollView, when textFiewl is tapped that is bellow the virtual keyboard. I call [self.scrollView setContentOffset:scrollPoint animated:YES];. To get the screen's visible area, i obviously need the KB size.
I am familiar with
NSDictionary *info = [notification userInfo];
CGSize kbSize = [self.view convertRect:
[info[UIKeyboardFrameBeginUserInfoKey] CGRectValue]
fromView:nil].size;
however, it doesn't work for me, because when a user taps on possibly half-hidden textfield, i don't receive the keyboard notification.
So i call the method in textFieldDidBeginEditing:, which is called before keyboard will send message, and so i don't know the KB size on first tap.
So the question is: is possible to get the KB size, without invoking corresponding notification?
Programmaticaly, not hardcoding.
You are doing it wrong.
You need to also listen for the keyboard show/hide notifications and then adjust your screen.
Here is a sample skeleton code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardChangedStatus:) name:UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardChangedStatus:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[nc removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - Get Keyboard size
- (void)keyboardChangedStatus:(NSNotification*)notification {
//get the size!
CGRect keyboardRect;
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
keyboardHeight = keyboardRect.size.height;
//move your view to the top, to display the textfield..
[self moveView:notification keyboardHeight:keyboardHeight];
}
#pragma mark View Moving
- (void)moveView:(NSNotification *) notification keyboardHeight:(int)height{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationBeginsFromCurrentState:YES];
CGRect rect = self.view.frame;
if ([[notification name] isEqual:UIKeyboardWillHideNotification]) {
// revert back to the normal state.
rect.origin.y = 0;
hasScrolledToTop = YES;
}
else {
// 1. move the view's origin up so that the text field that will be hidden come above the keyboard (you need to adjust the value here)
rect.origin.y = -height;
}
self.view.frame = rect;
[UIView commitAnimations];
}