CGRectOffset animation misbehaved when working with TextField - ios

The task is to move the textfield up when user done editing.
Right now, I have a text field textfield in the centre of the view, and a method moveTextFieldToTheTop.
Here is the code:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[_textField resignFirstResponder];
return NO;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self moveTextFieldToTheTop];
}
- (void)moveTextFieldToTheTop
{
[UIView animateWithDuration:0.3
animations:^{
_textField.frame = CGRectOffset(_textField.frame, 0, -100);
}];
}
Instead of moving 100px up from the centre, textfield would somehow appear 100px below the centre and move to the centre position.
I debugged the code, and find out
[_textField resignFirstResponder];; is the cause of this problem.
But I really can't find out why and how to solve this problem.
Can someone please help me?
Update
I was using auto layout when I came across this problem. If I uncheck use auto layout, problem solved.
But is there a way to solve this problem with auto layout checked?

With auto layout change your moveTextFieldToTheTop method with this:
- (void)moveTextFieldToTheTop
{
//TODO update _textField's constraint to move _textField 100pt up
[_textField setNeedsLayout];
[UIView animateWithDuration:0.3
animations:^{
[_textField layoutIfNeeded];
}];
}
if you are using storyboard, then connect constraint of _textField to view controller, and update the code TODO part with that constraint(you need to change constraint .const property by 100)
Update
Here is the example project with textfield, just run the example, touch on textfield to open keyboard, and then press return button on keyboard.
https://www.dropbox.com/s/x138ta2uy1z3bbo/ToolBarhighlightproblem.zip?dl=0

Related

Text jumps when animating position of UITextField subclass

When I animate the location of my UITextField subclass, the text in the field jumps out of step with the location of the UITextField holding it, which is very jarring and I can't figure out why it happens:
My subclass adds a button to the right hand side of the text field that when tapped calls a method on the view controller, which changes the textfield border colour and moves the text field up the screen by changing the top space constraint of the text field, and a couple of other views located above it.
[UIView animateWithDuration:0.3
animations:^{
self.tableViewBottomSpaceConstraint.constant = 0;
self.mainLabelHeightConstraint.constant = 0;
self.subLabelTopSpaceConstraint.constant = 0;
self.postCodeFieldTopSpaceConstraint.constant = 12;
[self.view layoutIfNeeded];
}];
i fixed this. change your code to this. It will work.
[UIView animateWithDuration:0.3
animations:^{
self.tableViewBottomSpaceConstraint.constant = 0;
self.mainLabelHeightConstraint.constant = 0;
self.subLabelTopSpaceConstraint.constant = 0;
self.postCodeFieldTopSpaceConstraint.constant = 12;
[self.view layoutSubviews];
}];
or if this doesn't work then instead of
[self.view layoutSubviews];
use the parent view of the text field and layoutSubviews. In my case this worked. I think this answer is eligible for the bounty. Thanks.
EDIT:
I found the reason of this. When we are trying to layoutIfNeeded it means its changing the outer layout first and after it changes its layout its changing the inner text of UITextField because we are not forcefully changing layout of all subviews of that text field. After all UITextField is made up of UIView and Label and other base elements. But when we trying to layoutSubviews its changing layout of all subviews simultaneously. Thats why the bouncing is gone.
It looks like for some reason your UI isn't in a settled state before the animation is triggered.
Try adding a call to [self.view layoutIfNeeded]; before your animation block, and use [self.view layoutIfNeeded]; at the end of your block rather than [self.view layoutSubviews]; which shouldn't really be used in this context.
For iOS 9 or above, this solve the issue
Objective-C:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField layoutIfNeeded]; //Fixes iOS 9 text bounce glitch
//...other stuff
}
Swift:
func textFieldDidEndEditing(_ textField: UITextField) {
textField.layoutIfNeeded() //Fixes iOS 9 text bounce glitch
//...other stuff
}
Google takes me here. Under #Mahesh Agrawal 's answer, #Andy comments a link that links to Here which is the best solution I can find for this problem.

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.

How to Use Autolayout to Animate Resizing a UITextView's Bottom Constraint When Content Has Been Scrolled

Background
I'm working on a quick and dirty notes app purely to try to understand autolayout. As such I am looking for an autolayout-specific solution to this problem.
I am quite sure that my terminology and understanding of this subject may be incorrect in places so if I misphrase or omit information through ignorance that would otherwise be helpful I am very happy to update this question with better specifics.
Short Problem Summary
This app is a simple note app. On the detail view of the note, there are two text input views, a UITextField, and a UITextView.
The goal is to use autolayout to animate a change of height to the UITextView when it is being edited (making room for the keyboard), and then animate the UITextView back to it's original size when editing is finished.
The animation code I have in place works, however when the UITextView is scrolled near to the bottom of the text the animation from "editing" size to "non-editing" size displays incorrectly durring the animation. (The final result of the animation, however is correct.)
I'm open to alternate "correct" ways of doing this if there's a common pattern for the solution. I am, however, looking for an autolayout solution which, I believe, means avoiding modifying the view's frame directly. (Could be wrong on that.)
Details and Code
A short video of the problem is available here:
http://pile.cliffpruitt.com/m/constraint_problem.mp4
This is the code performing the animation:
// self.bodyFieldConstraintBottom refers to an outlet referencing the UITextView's bottom constraint
// This animation occurrs when the text view is tapped
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
[self enterEditingMode];
[UIView animateWithDuration:2.35
animations:^{
NSLayoutConstraint *bottom_constraint = self.bodyFieldConstraintBottom;
bottom_constraint.constant = 216;
[self.view layoutIfNeeded];
}];
return YES;
}
// This animation occurrs when editing ends and the text field size is restored
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
[self exitEditingMode];
[UIView animateWithDuration:2.35
animations:^{
NSLayoutConstraint *bottom_constraint = self.bodyFieldConstraintBottom;
bottom_constraint.constant = 20;
[self.view layoutIfNeeded];
}];
return YES;
}
Full project source (in all it's messy glory) can be downloaded here:
http://pile.cliffpruitt.com/dl/LittleNotebooks.zip
Additional Comments
My understanding of cocoa terminology isn't the best so I'm having a hard time making google searches and docs searches effective. My best guess about the problem (based on observing the animation at a slow speed) is that it is related to a scroll offset somehow because unless the text is scrolled past a certain point, the problem does not manifest itself.
I have read quite a few SO question/answers including:
Resizing an UITextView when the keyboard pops up with auto layout
How to resize UITextView on iOS when a keyboard appears?
UIScrollView animation of height and contentOffset "jumps" content from bottom
The problem is that these answers either do not work ([self.bodyField setContentInset:UIEdgeInsetsMake(0, 0, 216, 0)]; seems to have no effect) or appear to rely on setting the frame of the UIText view which I believe is not supposed to be done when using autolayout.
Final Side Note
I've been at this off and on for about 4 days so my understanding and recollection of all I've read and tried is actually a little less clear than when I'd started. I hope I'm explaining this well enough to convey the issue.
EDIT:
I've noticed that this code actually gets somewhat close to the desired result:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
[self enterEditingMode];
[UIView animateWithDuration:2.35
animations:^{
[self.bodyField setContentInset:UIEdgeInsetsMake(0, 0, 216, 0)];
[self.view layoutIfNeeded];
}];
return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
[self exitEditingMode];
[UIView animateWithDuration:2.35
animations:^{
[self.bodyField setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
[self.view layoutIfNeeded];
}];
return YES;
}
The problem with this version is that the scroll indicator scrolls down past the visible area of the text content, meaning it gets "lost" behind the keybaord. Also, it does not help me understand the correct way to animate a UITextView (UIScrollView ?) bottom constraint.
The issue looks weird and I am really not sure whats the main issue but I found out that for the best results you should call [self.view setNeedsUpdateConstraints]; before animating view.
My example code to animate view when keyboard appears:
-(void)keyboardWillShow:(NSNotification *)notification {
CGSize kbSize = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//BH: iOS7 is messed up
CGFloat keyboardHeight = kbSize.width;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
keyboardHeight = kbSize.height;
}
self.centerYConstraint.constant = keyboardHeight;
[self.view setNeedsUpdateConstraints];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.view layoutIfNeeded];
[UIView commitAnimations];
}
I am using commit animations to animate view with same animationCurve as iOS is animating keyboard so view is moving 1 to 1 accordingly to keyboard. Also, please notice if statement for iOS8 vs iOS7 where Apple finally fixed window sizing.

Textfieldshouldreturn auto scroll screen

I use the code below. As it seems I have 5 uitextfields. Now for some reason when I clicked next, the view actually scrolled down automatically so I could see the textfield I was writing data with the keyboard. I thought this was default.
I added a lot of code in the uiview and added a button linking to another view. Somehow in the middle of that process my uiview lost its "auto-scroll-when-next-is-pressed" mechanism. I tried deleting my button and messed around a bit but couldn't find the problem.
Not sure if I should post the whole class.
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
[textField resignFirstResponder];
if (textField == self.firstOne) {
[self.secondOne becomeFirstResponder];
} else if (textField == self.secondOne) {
[self.thirdOne becomeFirstResponder];
} else if (textField == self.thirdOne) {
[self.fourthOne becomeFirstResponder];
} else if (textField == self.fourthOne) {
[self.fifthOne becomeFirstResponder];
}
return NO;
}
I also found some content on how to scroll screen programmatic by setting up coordinates. Not very viable in my opinion. I want it to be the way it was "Knowing where to scroll down automatically".
I found out that the reason is I added viewWillAppear method when I introduced the new button. That code didn't call the super method, so by just adding 1 line of code the problem was fixed
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// your code
}
I hope that add the ScrollView in View and next step add the 5 TextField in SubView of the UIScrollView such like as
[scrollView addSubView:textField1];
Next increase and decrease the scrollview content of set. Such as
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[scrollView setContentOffset:CGPointMake(0, 230) animated:YES];
}

How to remove delete button when editing UITableViewCell?

I want to customize my cell behavior - I want cell view to change and different buttons appear. I got half of it working - when I swipe I get the view to move.
But I have this delete button to the right side of cell, I want to get rid of it and use custom button instead of it. What should I use to remove it and where do I bind my button to do the same thing?
I tried using two methods, setEditing: and willTransitionToState, but that didn't help.
If I skip calling parent method in any of these, I don't get delete button as I want, but my view never returns to its original position after editing and other cells stop reacting to swipes. What do I need to do to fix this?
-(void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:YES];
if (editing) {
[UIView animateWithDuration:0.3 animations:^{
self.parentView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, 100, 0);
}];
} else {
[UIView animateWithDuration:0.3 animations:^{
self.parentView.transform = CGAffineTransformIdentity;
}];
}
}
-(void)willTransitionToState:(UITableViewCellStateMask)state
{
[super willTransitionToState:state];
if (state == UITableViewCellStateShowingDeleteConfirmationMask) {
[UIView animateWithDuration:0.3 animations:^{
self.parentView.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, 100, 0);
}];
}
if (state == UITableViewCellStateDefaultMask) {
[UIView animateWithDuration:0.3 animations:^{
self.parentView.transform = CGAffineTransformIdentity;
}];
}
}
Since your cell is a subclass of UITableViewCell, and you don't want to use the stock delete you probably want to disable it. The bare basic way would be to return no editing style for any of the cells.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
Some of the comments mentioned what you can do next.
Add an additional view that is below the main view of your cell.
Add a button on that view on the right in the same place the delete button was.
Use either a swipe gesture recognizer to do a basic swipe or a pan gesture recognizer
for dragging (normal behavior).
Update the top view frame based on the translations.
no you can't change the delete button that appears in default UITableViewCell.
Instead, create a customClass of UITableViewCell.
or,
Hack its subView and find any subView which is of class UIButton and title text "delete", then change it.

Resources