I have a search bar in my app in which I would like some animation to occur just before the keyboard shows up when the focus is placed in the search box. Is there a delegate method I can make use of to intercept before the keyboard is shown?
I am currently running the following code to detect when the UISearchBar has been activated:
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
NSLog(#"Begin Editing");
CGRect newFrame = searchBar.frame;
newFrame.origin.y = 0;
[UIView animateWithDuration:0.25
animations:^{
searchBar.frame = newFrame;
[searchBar layoutSubviews];
}
completion:^(BOOL finished){
NSLog(#"Done!");
}
];
}
Can I delay the showing of the keyboard in anyway? Maybe call a halt to it and then show it in the completion handler?
you need to add an notification center to you code.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
then declare a method named keyboardDidShow: and add the animation code to it.
there many options available. I guess
name:UIKeyboardWillShowNotification
is also available. just check it if its there and it should work.
Cheers happy coding.!!
Yes, there is also searchBarShouldBeginEditing:. You can do your animations, then return YES.
Related
No matter which settings I try to change, resignFirstResponder always forces the text to scroll to the top of a UITextView
I would like the keyboard to disappear but the content offset to remain the same.
Any solutions would be greatly appreciated.
This is caused by a UIScrollView bug in iOS 8. Hopefully in iOS 9 they fix it. I only assume that its a bug because resignFirstResponder didn't have this behavior in iOS 7. Maybe its a feature.
The only way I found to prevent resignFirstResponder and setText from resetting the contentOffset was the following:
Swift:
textView.layoutManager.allowsNonContiguousLayout = false
Objective C
textView.layoutManager.allowsNonContiguousLayout = NO;
Another reason I think its a bug is because the documentation says that it is set to NO by default, but when you print out the variable without setting it, its true.
More info on NSLayoutManager can be found here
in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
add this function
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[_textView scrollRangeToVisible:NSMakeRange([_textView.text length], 0)];
}];
}
I've been wondering if it is possible to replicate the behavior of Apple's iOS5 keyboard in the messages app, without using any private API calls. When you scroll down past the keyboard in the messages app, the keyboard will collapse leaving more room to see messages - try it to see.
I couldn't find anything that points towards making this without having to start jumping through some serious hoops to get an instance of the Keyboard's View. And I'm pretty sure Apple wouldn't be happy with that.
In addition to the answer given below you can see a fully baked xcode project of my implementation here:
https://github.com/orta/iMessage-Style-Receding-Keyboard
In iOS 7 there is a keyboardDismissMode property on UIScrollView.
So just set it to "UIScrollViewKeyboardDismissModeInteractive" and you'll get this behavior. Works in UIScrollView subclasses such as UITableView.
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
Swift 3:
tableView.keyboardDismissMode = .interactive
Or change it in storyboard (if using it) in attributes inspector for your UIScrollView subclass.
This is an incomplete solution, however it should give you a good starting point.
Add the following ivars to your UIViewController:
CGRect keyboardSuperFrame; // frame of keyboard when initially displayed
UIView * keyboardSuperView; // reference to keyboard view
Add an inputAccessoryView to your text controller. I created an small view to insert as the accessoryView:
accView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
accView.backgroundColor = [UIColor clearColor];
textField.inputAccessoryView = accView;
I added the above code to -(void)loadView
Register to receive UIKeyboardDidShowNotification and UIKeyboardDidHideNotification when view is loaded:
- (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];
return;
}
Add methods to specified as the selectors for the notifications:
// method is called whenever the keyboard is about to be displayed
- (void)keyboardWillShow:(NSNotification *)notification
{
// makes keyboard view visible incase it was hidden
keyboardSuperView.hidden = NO;
return;
}
// method is called whenever the keyboard is displayed
- (void) keyboardDidShow:(NSNotification *)note
{
// save reference to keyboard so we can easily determine
// if it is currently displayed
keyboardSuperView = textField.inputAccessoryView.superview;
// save current frame of keyboard so we can reference the original position later
keyboardSuperFrame = textField.inputAccessoryView.superview.frame;
return;
}
Add methods to track touched and update keyboard view:
// stops tracking touches to divider
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect newFrame;
CGRect bounds = [[UIScreen mainScreen] bounds];
newFrame = keyboardSuperFrame;
newFrame.origin.y = bounds.size.height;
if ((keyboardSuperView.superview))
if (keyboardSuperFrame.origin.y != keyboardSuperView.frame.origin.y)
[UIView animateWithDuration:0.2
animations:^{keyboardSuperView.frame = newFrame;}
completion:^(BOOL finished){
keyboardSuperView.hidden = YES;
keyboardSuperView.frame = keyboardSuperFrame;
[textField resignFirstResponder]; }];
return;
}
// updates divider view position based upon movement of touches
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch;
CGPoint point;
CGFloat updateY;
if ((touch = [touches anyObject]))
{
point = [touch locationInView:self.view];
if ((keyboardSuperView.superview))
{
updateY = keyboardSuperView.frame.origin.y;
if (point.y < keyboardSuperFrame.origin.y)
return;
if ((point.y > updateY) || (point.y < updateY))
updateY = point.y;
if (keyboardSuperView.frame.origin.y != updateY)
keyboardSuperView.frame = CGRectMake(keyboardSuperFrame.origin.x,
point.y,
keyboardSuperFrame.size.width,
keyboardSuperFrame.size.height);
};
};
return;
}
Disclaimers:
When resigning as first responded, the keyboard moves back to its original position before sliding off screen. To make dismissing the keyboard more fluid, you first need to create an animation to move the keyboard off of the screen and then hide the view. I'll leave this part as an exercise to the readers.
I've only tested this on the iOS 5 simulator and with an iPhone with iOS 5. I have not tested this with earlier versions of iOS.
The SlidingKeyboard project I created to test this concept is available from GitHub in the examples directory of BindleKit:
https://github.com/bindle/BindleKit
Edit: Updating example to address first disclaimer.
Vladimir's simple solution will hide the keyboard as the user scrolls down. However to finish the question regarding iMessage, in order to keep a TextField always visible and anchored to the top of the keyboard, you need to implement these methods:
- (UIView *) inputAccessoryView {
// Return your textfield, buttons, etc
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
Here's a good tutorial breaking it down more
I have one view window which I created in the interface builder. I created a UIScrollView which fills the entire window and dragged some other items into it, including a UITextView. The problem I encountered was that when I click to write into the TextView the keyboard blocks the view of the TextView, hence the use of a ScrollView.
Now I've searched around quite a bit and think I know what I need to do but if I'm doing it right is another matter.
I get the bounce, that is I can drag everything that's in the ScrollView and it will bounce back. When I then press to write in the TextView the keyboard pops up, this shrinks the ScrollView to "screen size" - "keyboard size" (I know this happens as I haven't implemented the "do this once I hide the keyboard" function yet, so when I hide the keyboard the ScrollView now ends where the keyboard started). But even though the view size is now smaller than the content size it does not scroll, simply continues to bounce.
Here below you can see the code I'm using. I call the registerForKeyboardNotifications in viewDidLoad.
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification *)n
{
NSLog(#"WoopWoopWoop");
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.mainScrollView.frame;
viewFrame.size.height -= (keyboardSize.height);
mainScrollView.bounces = YES;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.4];
[self.mainScrollView setFrame:viewFrame];
[UIView commitAnimations];
}
I've tried setting the content view to some arbitrary size such as
[mainScrollView setContentSize:CGSizeMake(3200.0,2300.0)];
but that has had no effect...
Any ideas?
Hi, you don't need to make use of notifications. Just make use of the UITextFieldDelegate protocol methods. You can set the content Offset for the scrollView in those methods.
For example:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
//Check the necessary textfield and then change yValue accordingly
[scrollView setContentOffset:CGPointMake(0,yValue) animated:YES];
return YES;
}
when I click to write into the TextView the keyboard blocks the view of the TextView, hence the use of a ScrollView.
First, I would suggest that this use of UIScrollViews is not necessary (if you only have a UITextView to display. Also, remember that UITextView is a subclass of UIScrollView).
You can achieve repositioning and resizing of your UITextView by configuring it as a subview of a UIView instead. Enable autoresizesSubviews on your UIView and configure both views' springs and struts via the IB Inspector. The UIView container should take all the available space.
Using the same approach as described in your question, when the UIView is resized, it should automatically adjust the UITextView's frame as well.
Now, even if you do need to have a view hierarchy with a UIScrollView at the top, I would still suggest to wrap that into a plain UIView container, and configure autoresizing as I mentioned above.
Hope that helps!
so, basically I need to know if there is a way to have a observer o another method that is called when the keyboard is hidden.
The problem i have is that after dismissing the Keyboard, I commit 2 Animations, one to take the view to the original position (since I move up the view so the user can see the textfield while typing) and an Animation Flipping the View but the Flip occurs before the Keyboard is fully hidden so I have a little graphic glitch.
I've tried sleep(), and another wait methods without luck.
The Code Basically is this
- (BOOL)textFieldShouldReturn:(UITextField *)textFieldi{
[textFieldi resignFirstResponder];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[self.view exchangeSubviewAtIndex:1 withSubviewAtIndex:0];
CuantoFaltaiOSAppDelegate * del = [CuantoFaltaiOSAppDelegate instance];
del.headerView.frame = CGRectMake(0, 20, del.headerView.frame.size.width, del.headerView.frame.size.height);
[UIView commitAnimations];
return YES;
}
The problem is that the Keyboard isn't fully Hide and the Flip is perfomed, so i need a way to wait for it.
Register for the UIKeyboardDidHideNotification notification.
[[NSNotificationCenter defaultCenter] addObserver:(id)
selector:(SEL)
name:(NSString *)
object:(id)];
Example:
Subscribe to the UIKeyboardDidHideNotification as follows (put this in your viewWillAppear: method):
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
This assumes you have a method called keyboardDidHide: (this is where your animation logic will reside)
The following function is a method of a class called TitleOverlay - which is a transparent overlay with a textView.
The function shows the overlay by animating its alpha, and in parallel uses the animationWillStart property of the animation to show the keyboard.
On 3G phones, the first time this function is called, there is some lag before the keyboard shows. In fact, I think the animation to show the overlay and show the keyboard are being serialized. I tried setting the length of the overlay alpha animation to various lengths, and the keyboad always shows after the animation completes.
Basically, the first time, there is lag. On all subsequent times, the keyboard and the overlay animations occur in parallel, and it looks nice.
WHat can I do to fix this?
- (void) showOverlay {
[[self superview] bringSubviewToFront:self];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[nc addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[UIView beginAnimations:nil context: nil];
[UIView setAnimationDuration: .5];
[UIView setAnimationDelegate:titleField];
[UIView setAnimationWillStartSelector:#selector(becomeFirstResponder)];
self.whiteBlock.alpha = 1;
[UIView commitAnimations];
}
The lag when displaying a keyboard for the first time in an iPhone application is a known issue. There is a hack to work around this, as pointed out in that question.