Is it possible to receive a local notification when Predictive is enable/disabled.
I have a UITextView and when Predictive is enabled, the inputAccessoryView of this textView moves up and it hides the last line in textView. If its possible to get notification that Predictive has changed, I can resize the textView.
I searched but could not find any way to receive the notification.
I also did not find any delegate methods for this in UITextViewDelegate.
Any help would be highly appreciated.
Why not move up little bit your view when you start typing and solved this issue :)?
Use UITextFieldDelegate and use this code (you can animate this if you want)
- (void)textFieldDidBeginEditing:(UITextField *)textField{
CGRect rect = self.view.frame;
rect.origin.y = - 30; //enter pixels number to pushup your view
self.view.frame = rect;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
CGRect rect = self.view.frame;
rect.origin.y = 0; //return to 0.0 position.
self.view.frame = rect;
}
Have you tried to listen to the notifications received from UIKeyboardWillShowNotification and UIKeyboardWillHideNotification?
Related
I'm debugging someone else's code - sorry I have very limited Objective-C experience.
#pragma mark - Keyboard events
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSLog(#"Keyboard a Notification user Info %#", info);
printf("keyboardWasShown \\\\\\\\\\\\\\\\\\\\\n");
NSLog(#"textInputView: y: (%.f), height: (%.f), kbHeight: (%.f)",
textInputView.frame.origin.y, textInputView.frame.size.height, kbSize.height);
[UIView animateWithDuration:2.0f animations:^{
if (keyboardNewLine){
bubbleTableFrame = originalBubbleTableFrame;
}
CGRect frame = originalTextViewFrame;
int difference = 0;
if (IsIphone5){
difference = -42;
frame.origin.y -= kbSize.height + difference;
} else {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f) {
difference = 42;
frame.origin.y -= kbSize.height + difference;
} else {
frame.origin.y -= kbSize.height + 110;
difference = 42;
}
}
textInputView.frame = frame;
frame = bubbleTableFrame;
frame.size.height -= kbSize.height + difference;
bubbleTable.frame = frame;
}];
NSLog(#"textInputView: y: (%.f), height: (%.f), kbHeight: (%.f)",
textInputView.frame.origin.y, textInputView.frame.size.height, kbSize.height);
printf("keyboardWasShown //////////\n");
[bubbleTable scrollBubbleViewToBottomAnimated:YES];
}
When I tap the text input field to bring up the keyboard, the field should move up to just above the keyboard - sometimes. It all depends on the which keyboard is loading first.
The text field without keyboard:
After tapping the text field, I expect:
However the text field stays at the bottom of the screen, leaving only the placeholder:
Strange enough, if I drag down the QuickType row, the text field suddenly appears!
But if I exit from this view and come back afterwards, once again the text field is stuck at the bottom (and guess what, it jumps up if I drag UP the QuickType row):
Switching to another keyboard (input method) by tapping the globe icon always helps to bring up the text field:
It seems that third-party keyboards are not affected:
You can see that I keep monitoring textInputView.frame.origin.y to see what goes wrong. It changes from 472 (no keyboard) to 261 (English keyboard) but the text field simply doesn't go up.
I don't think it is behind the placeholder (if any) because when I tap the white area beside the bubbles, the keyboard moves down and unveils the text field stuck at the bottom.
Someone suggested adding setNeedsDisplay, setNeedsLayout, etc. but none helped.
Thanks in advance.
Eventually I turned off Auto Layout as suggested by someone:
https://www.facebook.com/groups/cocoahk/permalink/1104922892867587/
It worked. Though I needed to adjust the positions of all other objects.
I have a couple UITextFields that will be hidden by the keyboard when it pops up, so I implemented the UIKeyboardWillShowNotification and UIKeyboardWillHideNotification and sent them to their respective methods:
- (void)keyboardWillShow:(NSNotification*)notification
{
CGFloat height = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
keyBoardHeight = height;
}
- (void)keyboardWillHide:(NSNotification*)notification
{
CGFloat height = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
keyBoardHeight = height;
}
I then have my textfields delegating to this method:
//TextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
float keyboardOffset = [self offsetForKeyboard:textField.frame.origin.y withHeight:textField.frame.size.height];
NSLog(#"%f, %f", keyBoardHeight, keyboardOffset);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.1];
self.view.frame = [Global rect:self.view.frame withNewY:-[self offsetForKeyboard:textField.frame.origin.y withHeight:textField.frame.size.height]];
[UIView commitAnimations];
}
The code runs properly, but when I run the code, the keyboardWillShow: method runs after the textFieldDidBeginEditing: method. Because of this, keyboardHeight is set to 0 the first time the code runs, and so the offset I calculate is way off.
How can I make the keyboardWillShow: method run before the textFieldDidBeginEditing: method? Is there another delegate method that I can use instead?
Sorry, but no there's no way to do that. You have to do your animations or whatever you do for keyboard handling inside the notification observer.
Here's what Apple recommends and works fine for me in all cases I've encountered upto now.
Apple's Keyboard Guide
For anyone else who is trying to do this, I found a way:
Maintain a weak reference to the currently editing text field:
UITextField* editingTextField;
- (void)textFieldDidBeginEditing:(UITextField*)textField
{
editingTextField = textField;
}
- (void)textFieldDidEndEditing:(UITextField*)textField
{
editingTextField = nil;
}
Then just reference the weak text field while it is open in the keyboardWillShow: method to calculate the appropriate offsets and move the view accordingly.
- (void)keyboardWillShow:(NSNotification*)notification
{
//Use editingTextField's frame here
}
Simply use IQKeyboardManager. It is a single line code for all textfield in any view.Link: https://github.com/hackiftekhar/IQKeyboardManager
I am experiencing a strange error on iOS 8 when trying to synchronize an animation in tandem with the keyboard moving up after selecting a textfield.
Specifically, I am trying to get the height of the keyboard in order to know how far up to move the text field by using the following code after registering for the keyboardwillshow notification:
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.keyboardHeight = keyboardSize.height;
[self moveToolbarUp];
}
-(void)moveToolbarUp
{
self.keyboardExpanded = YES;
CGRect frame = self.toolbar.frame;
DLog(#"keyboard height now:%f",self.keyboardHeight);
frame.origin.y = (self.view.frame.size.height-toolbarHeight-self.keyboardHeight);
[UIView animateWithDuration:0.1 animations:^{
self.toolbar.frame = frame;
}];
}
However, if I try to set a break point at the keyboardwillshow method, I can see that the keyboard is already all the way up when the method is called, and the animation is therefore delayed (the keyboard pops up and then a second or so later, the textfield follows).
Has anybody else experienced this error? I am running on an iPhone 5s, iOS 8.0.2.
Thanks!!
It's not an error. The fact is that you can remove your animateWithDuration call. In iOS 8, keyboardWillShow: is called inside the keyboard's animation. You don't have to synchronize anything; anything you do will be part of the animation, automatically.
This code was working beautifully in ios 7. However, with ios8 and xcode 6.0.1 it has stopped working. When a user clicked on a text field to enter text, the field animated to float just above the top of the keyboard so they can see what they are typing. Any thoughts on why this fails to work now. I can see it start to animate for a split second, but then the textfield disappears. Frustrating.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
textField.frame = CGRectMake(textField.frame.origin.x, (textField.frame.origin.y - 200.0),
textField.frame.size.width, textField.frame.size.height);
_searchBtn.frame = CGRectMake(_searchBtn.frame.origin.x, (_searchBtn.frame.origin.y - 200.0),
_searchBtn.frame.size.width, _searchBtn.frame.size.height);
[UIView commitAnimations];
textField.alpha = .75;
}
The problem is that your code adjusts your TextField's position by a fixed value of 200.0
This was probably great for iOS7 but things have changed in iOS8 for two reasons:
The system keyboard has an additional view for showing predicted words while typing
Custom keyboards can be as high as the developer chooses
You need to change your approach move moving the location of your TextField whenever the keyboard is shown or hidden using the following two notifications:
UIKeyboardWillShowNotification
UIKeyboardWillHideNotification
In the following thread I explain the problems that can arise and how to properly move your views around as the keyboard opens:
can't get correct value of keyboard height in iOS8
EDIT 1:
Assuming the textbox has an outlet called "yourTextBox", the code to modify the position of your textbox could look something like:
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat keyboardHeight = <<calculated keyboard height as previously discussed>>;
CGFloat textBoxHeight = _yourTextBox.frame.size.height;
// Change the current frame of your textbox in order to reposition it
CGFrame textBoxFrame = _yourTextBox.frame;
textBoxFrame.origin.y = screenHeight - keyboardHeight - textBoxHeight;
_yourTextBox.frame = textBoxFrame;
Note: If you are using AutoLayout constraints to position your subviews you will need to avoid modifying the frame and change your constraints instead. Post if you are having problems in this area because it can get tricky.
i'm working on a project where i have a tableview and a uitextfield.
I'm applying the following method when the uitextfield gain/loose the focus :
-(void)enableInset {
CGFloat offSet = -30.0f;
UIEdgeInsets inset = UIEdgeInsetsMake(placesMapView.frame.size.height - offSet, 0.0f, 0.0f, 00.f);
// Updating the tableView position.
placesTableView.contentInset = inset;
placesTableView.contentOffset = CGPointMake(0.0f, -(placesMapView.frame.size.height - offSet));
placesTableView.scrollIndicatorInsets = inset;
}
and
- (void)disableInset {
CGFloat offset = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
UIEdgeInsets inset = UIEdgeInsetsMake(offset, 0.0f, 0.0f, 00.f);
placesTableView.contentInset = inset;
placesTableView.contentOffset = CGPointMake(0.0f, -offset);
placesTableView.scrollIndicatorInsets = inset;
}
The enableInset method is called in viewDidLayoutSubviews.
then when i call disableInset and enableInset, the UITableView can not be scrolled anymore.
What did i did wrong ? Any idea where i can look for some answer ?
EDIT :
If it can help, i added the project on github :
https://github.com/Loadex/PlaceViewer
To re-produce the bug :
Scroll the list, tap on the search bar, hit cancel, try to scroll again the list.
Weirdly click on the filter button, when the UIActionSheet is dismissed, the scroll is working again.
While looking for a solution to your problem i noticed that the bottom part of the contentInset of your placesTableView kept changing through the different states. It was 0 when in the initial state where you could see the map, and the tableView was behaving as expected. It got set to 216 when the keyboard came up after tapping the search field. I figured this was some automated communication between the tableView and the keyboard (through Notifications or something you did in PlacesQueryTableViewController). This is fine because we want the bottom inset to be set to the top of the keyboard when it appears. Now, here comes the buggy part. When I tapped the cancel button, the contentInset.bottom got set to -216.
I can't quite explain why this happens, but I suspect it has something to do with how that automatic change of the inset is implemented. I suspect that it does something like tableView.contentInset.bottom -= heightOfKeyboard, and that probably happens when the animation is finished, and not before. The source of your problem is that you change that bottom of contentInset before the animation is done, and thus before that automatic change has happened. So you're setting the bottom to 0 as soon as the user taps cancel. Then the system comes in and reduces it by the height of the keyboard, which turns out to be 216. That's what I think is happening anyway.
To fix this problem, avoid changing the bottom part of the contentInset and just change the top part. placesTableView.contentInset.top is readOnly, but if you do it like in the code below, you can get around that. I have just changed two lines of code in each method, the ones that have to do with the inset. Hopefully you see what I did.
-(void)enableInset {
NSLog(#"Enabling insets");
// Setting the tableView to overlay the map view
CGFloat offSet = [placestableViewController tableView:placestableViewController.tableView heightForRowAtIndexPath:nil] - 30.0f;
UIEdgeInsets inset = placesTableView.contentInset; // UIEdgeInsetsMake(placesMapView.frame.size.height - offSet, 0.0f, 0.0f, 0.0f);
inset.top = placesMapView.frame.size.height - offSet;
// Updating the tableView position.
placesTableView.contentInset = inset;
placesTableView.contentOffset = CGPointMake(0.0f, -(placesMapView.frame.size.height - offSet));
placesTableView.scrollIndicatorInsets = inset;
placesMapView.hidden = NO;
[placestableViewController loadObjects];}
- (void)disableInset {
NSLog(#"Disable insets");
CGFloat offset = self.navigationController.navigationBar.frame.size.height + [UIApplication sharedApplication].statusBarFrame.size.height;
UIEdgeInsets inset = placesTableView.contentInset;// UIEdgeInsetsMake(offset, 0.0f, 0.0f, 0.0f);
inset.top = offset;
placesTableView.contentInset = inset;
placesTableView.contentOffset = CGPointMake(0.0f, -offset);
placesTableView.scrollIndicatorInsets = inset;
// Hidding the map while in search
placesMapView.hidden = YES;}
.
BTW, if you want to know how I found the contentInset values at the different states, it's quite simple. What I did was to set myself as the delegate of placesTableView in - (void)viewDidLoad like this placesTableView.delegate = self;. I also had to change the #interfacestatement to #interface KrackMapViewController () <UITableViewDelegate> to say that we conform to the UITableViewDelegate. Now, here's the trick: UITableViewDelegate conforms to UIScrollViewDelegate. That means we can implement methods of the scroll view delegate. The one that is particularly interesting is this one:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"Did scroll with insetTop: %f, insetBottom: %f, contentOffset: %f", placesTableView.contentInset.top,
placesTableView.contentInset.bottom,
placesTableView.contentOffset.y);
}
That lets us know when you start dragging the tableView, and in there simply NSLog out the different parameters.
I hope this was helpful. Let me know if this works for you.
After a few research here is what I noticed:
The TableView when the keyboard is released is not scrolling because the tableview seems to believe that it is displayed on the entire screen. I tried to add more data in the tableview and we can see that the view is scrolling a little.
What I believe happened is that when the keyboard is hidden, some automatic calls are done and messing with what I set in my enableInset method. Here is my working solution:
I registered for the hideKeyboard event:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
and in the callback I called enableInset:
- (void)keyboardDidHide: (NSNotification *) notif{
[self enableInset];
}
And the view is scrolling back again.
Any explanation about this are welcome.