UITextField repositions itself when resigning responder - ios

My main controller is a UITextFieldDelegate and animates a UITextField when its editing status changes. In the storyboard the view's original position is in the centre of the screen (vertically and horizontally), when it is being edited I position it to the top of the screen. If I now complete the "Go" action from the keyboard, resign first responder on the text field, the text field pops back to its original position. I have tried retaining the frame of the text field in textFieldShouldEndEditing, but it continues to go back to its original position. How can I keep the view in the new position, even when the keyboard resigns?
I animate the view like this
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
if ([textField isEqual: _toField] && !alreadyAnimated) {
[UIView beginAnimations:#"editFieldAnimation" context:nil];
[UIView setAnimationDuration:0.2f];
// move up to field
CGRect textFieldFrame = [_toField frame];
textFieldFrame.origin.y = 58; // default frame top margin
_toField.frame = textFieldFrame;
[UIView commitAnimations];
alreadyAnimated = YES;
}
return YES;
}

Related

Does UIScrollview works correct with UIStatusbar?

my problem is related with UIScrollview. lets describe it,
I have signup screen which has a scrollview, initially scrolling is not enabled. when keyboard appears I will enable scrollview and when keyboard hides again I am disabling scrolling. my scrollview’s width and height is same as its default view, I have applied horizontal, and vertical centre in container as well as top, bottom, leading and trailing edges are zero (i.e. it is equal to default view). I have a signup button which navigates to signup screen, and applied bottom constraints (bottom space constraints = 0), also I m using keyboard notification for appear and hide.
Actual Problem:
when tap textfield keyboard appears, scrollview scrolls, and when I dismiss the keyboard the scrollview came down, but this time the signup button will move little bit up (like bottom space has 20 points constraints).
First time its like scrollview starts after status bar, but when keyboard appears and hides its like scrollview is renders over view including status bar.
Do I need to add any constraints related to Top/Bottom Layout Guide in IB?
or do I need to add any constraints related to in viewDidLoad
Code for Keyboard notification.
-(void)keyboardWillShow:(NSNotification *)notification {
[self.navigationController.navigationBar setBackgroundImage:nil
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = nil;
self.ContentScrollView.scrollEnabled=YES;
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.ContentScrollView convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(self.ContentScrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compatibility between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0.0 options:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] animations:^{
self.ContentScrollView.contentInset = newContentInsets;
self.ContentScrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _activeField should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _activeField in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_activeField) {
CGRect controlFrameInScrollView = [self.ContentScrollView convertRect:_activeField.bounds fromView:_activeField]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, 0); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = (controlFrameInScrollView.origin.y - self.ContentScrollView.contentOffset.y)+10;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = self.ContentScrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
CGFloat maxScrollViewHeight = MAX(self.ContentScrollView.frame.size.height, self.ContentScrollView.contentSize.height);
newContentOffset.y = MIN(newContentOffset.y, maxScrollViewHeight - scrollViewVisibleHeight);
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.origin.y < self.ContentScrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = self.ContentScrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.origin.y;
[self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
} completion:NULL];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
[UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]doubleValue ] delay:0.01 options:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]intValue] animations:^{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.ContentScrollView.contentInset = contentInsets;
self.ContentScrollView.scrollIndicatorInsets = contentInsets;
CGPoint scrollPoint;
self.ContentScrollView.scrollEnabled=NO;
scrollPoint = CGPointMake(0.0, 0.0);
[self.ContentScrollView setContentOffset:scrollPoint animated:YES];
} completion:^(BOOL finished){
__weak typeof(self) weakSelf=self;
[weakSelf.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
weakSelf.navigationController.navigationBar.shadowImage = [UIImage new];
}];
}
Image
If further required I will send the screen shots of before and after keyboard notification.
Thank You.
From Documentation
A Boolean value that indicates whether the view controller should
automatically adjust its scroll view insets.
Declaration
#property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets
Discussion
Default value is YES, which allows the view controller to adjust its
scroll view insets in response to the screen areas consumed by the
status bar, navigation bar, and toolbar or tab bar. Set to NO if you
want to manage scroll view inset adjustments yourself, such as when
there is more than one scroll view in the view hierarchy.
Write self. automaticallyAdjustsScrollViewInsets=NO; in viewDidLoad and try

How can I make a table view appear when a button is pressed/tapped?

I am trying to make a UITableView appear when a user taps on a button and disappear when the button is re-tapped.
I implemented the following code but nothing seems to appear when I tap the button.
- (IBAction)dropDown:(UIButton *)sender
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.6];
CGAffineTransform transfrom = CGAffineTransformMakeTranslation(0, 200);
self.markersTableView.transform = transfrom;
self.markersTableView.alpha = self.markersTableView.alpha * (-1) + 1;
[UIView commitAnimations];
}
What may potentially be the issue?
EDIT:
I was able to make the UITableView appear and disappear by adding self.markersTableView.hidden = YES; in viewDidLoad() and self.markersTableView.hidden = NO; in the IBAction method.
However, the table view disappears when I initially tap on the button as shown in the screenshot:
The fading of the rows is an indication it is moving down the screen, and then it disappears.
It only reappears when I re-tap on the UIButton the 2nd time.
Any clues?
Don't use a transform on your table view. That will make it LOOK like it's in a different position, but it won't respond to taps correctly.
Instead, use the newer UIView block-based animation methods and change the view's center.
The code might look like this (if you're NOT using auto-layout)
[UIView AnimateWithDuration: .2
animations: ^
{
CGPoint center = self.markersTableView.center;
center.y += 200;
self.markersTableView.center = center;
}
];
If you're using auto-layout, though, that won't work and you will need to animate the view's position using constraints.
From memory, here's an outline of how to do auto-layout based animations: You would create a vertical position constraint on your table view and connect the constraint to an IBOutlet in your view controller. In your animation code you change the constant of the constraint (the vertical position) and then in the animation block, send the view a needsLayout message.

Decrease size of UITextView to reveal UIButton

I have a text view in my app that has a done button beside it to resign the keyboard. Basically, rather than having the done button permanently beside the text view, I would like the text view to decrease in width when tapped, and then a done button would appear in the space. Then when the user taps the screen or the done button, the button disappears and the text view increases to it's normal size again.
I have already implemented the code for making the button appear when the user starts typing but I would like to change this so that it appears when they tap the text view and I also need help with adding the animation to shrink the text view.
Thanks.
Implement your textview's delegate method textViewShouldBeginEditing:. Then in that method, do something like this:
button.alpha = 0.0f;
button.hidden = NO;
[UIView animationWithDuration:0.3f animations:^{
NSInteger padding = 5;
CGRect textViewFrame = textView.frame;
textViewFrame.width -= CGRectGetWidth(button.frame) - padding;
// Edit
textView.frame = textViewFrame;
// and just to fade the button in as the text field shrinks
button.alpha = 1.0;
}];
And I would do the opposite when you click the button to return the text field to the correct width

UIKeyboard Disabling Touch Events

When the keyboard is displayed in my app, no touches will work in my view. I will tap a UITextField and the keyboard will be presented. Now that it is displayed, I cannot tap on other textfields,buttons or select text even in the active textfield.
Any ideas what may cause this
Thanks.
UPDATE 1:
I have found that because I animate the view upwards a little when the keyboard is displayed this is causing a problem. I have the master, view controller view. Inside this is formContainerView which contains my two UITextFields and UIButton.
I animate formContainerView up so that my fields aren't hidden behind the keyboard. I run the following code to do this:
[UIView animateWithDuration:duration delay:0 options:animationOptionsWithCurve(curve) animations:^{
[self.formContainerView setFrame:CGRectOffset(self.formContainerView.frame, 0, -220.0f)];
}
completion:^(BOOL finished) { }];
So I just offset the view by 220 pixels. If I set this to 0, i.e. don't animate the position, all touches work. But by moving the view up, all touches fail to work.
Why?
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if ([txtfld_firstname isFirstResponder])
{
[txtfld_firstname resignFirstResponder];
[txtfld_secondname becomeFirstResponder];
}
return YES;
}
first set to the delegate for the textfield.
and after that write the above method when you click on the first textfield and after that press return button on the keyboard this (textfield delegate)method call and your keyboard disable.

UISearchBar with UISearchDisplayController animates outside screen

I have standard iPad view controller which has a custom navigation bar at the top. In the xib-file I've added a UISearchBar aligned to the right edge of the view. The search bar is 320px in width. I init a searchdisplaycontroller like this:
// Search display controller
self.mySearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar
contentsController:self];
_mySearchDisplayController.delegate = self;
_mySearchDisplayController.searchResultsDataSource = self;
_mySearchDisplayController.searchResultsDelegate = self;
The problem is that when I press the search bar, the bar resizes to be the full width of the entire view, but keeps its x-position. This means that it stretches far outside the screen. I'm guessing it has something to do with the "Cancel" button that slides in next to a search bar. If I place the search bar to the far left in the screen, it animates to the full width of the screen and the cancel button is visible.
Anyone has a solution for this?
You can animate the frame of your UISearchBar in the searchDisplayControllerWillBeginSearch method to correct its position like this:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
// animate the search bar to the left ie. x=0
[UIView animateWithDuration:0.25f animations:^{
CGRect frame = controller.searchBar.frame;
frame.origin.x = 0;
controller.searchBar.frame = frame;
}];
// remove all toolbar items if you need to
[self.toolbar setItems:nil animated:YES];
}
and the animate it back again when finished searching:
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
// animate search bar back to its previous position and size
// in my case it was x=55, y=1
// and reduce its width by the amount moved, again 55px
[UIView animateWithDuration:0.25f
delay:0.0f
// the UIViewAnimationOptionLayoutSubviews is IMPORTANT,
// otherwise you get no animation
// but some kind of snap-back movement
options:UIViewAnimationOptionLayoutSubviews
animations:^{
CGRect frame = self.toolbar.frame;
frame.origin.y = 1;
frame.origin.x = 55;
frame.size.width -= 55;
controller.searchBar.frame = frame;
}
completion:^(BOOL finished){
// when finished, insert any tool bar items you had
[self.toolbar setItems:[NSArray arrayWithObjects: /* put your bar button items here */] animated:YES];
}];
}
I have answered a similar question, you can check it here, I've put some images too.
The only thing you have to do is to adapt the code for the iPad.

Resources