In our question module I need to resize and animate UIView when user clicked answers which are represented by tableview. I have read some related questions and applied their solution but none of them worked for me.
The problem is uiview doesn't appear at first click but if user click same answers 2 times or more it appears because in second click on same answers does not change the frame.
so basically if the feedback of answer change, height of the uiview gonna be recalculated and I guess it is blocking animation.
my view hierarchy:
http://i.imgur.com/Oho6Hob.png
method which changes the constraints of views and textview:
self.feedbackLabelWrapperHeight.constant = height + 45;
self.feedbackViewHeight.constant = height + 45 + 12;
int y = height;
[self.feedbackView setFrame:CGRectMake(50,self.scrollView.frame.size.height + self.scrollView.frame.origin.y -(y+40),self.feedbackView.frame.size.width,(y+40))];
animation method:
[UIView beginAnimations:#"feedback" context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationDelay:delay];
[self.view layoutIfNeeded];
[UIView commitAnimations];
self.isFeedbackViewVisiable = YES;
I'm calling these two methods in didSelectRowAtIndexPath method in these order:
and labelHeightOfResponse parameter is the calculated height of related label or textview
[self setFeedbackConstraintHeight:labelHeightOfResponse];
[self feedbackViewAppearAnimationWithDelay:0.2 yPosition:labelHeightOfResponse];
I would really appreciate help here.
Thanks!
after spending a week I've added a constraint which does nothing. I don't know why but it solved animation blocking furthermore it worked perfectly even I deleted layoutIfNeeded.
Related
I want to animate a view to a specified origin when ever someone touched it and then comeback to its original position whenever user touched it again. I am using AutoLayout in my storyboard to align my views.
It first go upward with perfect position but does not come back to its original position perfectly.
I store the staring origin value in a CGFloat variable in my viewDidLoad method and then re assign that object to bring back the view.
Here is my code
Animation for upward (This is working perfect)
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
CGRect frame = _pickLocationView.frame;
frame.origin.y = _cityLabelView.frame.origin.y;
_pickLocationView.frame = frame;
[UIView commitAnimations];
Animation for Downward. (This method has some issue)
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
CGRect frame = _pickLocationView.frame;
frame.origin.y = kDefaultOriginOfPickLocationView;
_pickLocationView.frame = frame;
[UIView commitAnimations];
A suggestion:
Use the method - [self setNeedsLayout] before the animation starts.
The frame is not guaranteed to have its final dimensions and position in viewDidLoad. Use viewDidLayoutSubviews to set your original values instead. Note that viewDidLayoutSubviews can be called multiple times if the bounds of your view changes.
In your case you could also just save the original value just before you start the first animation.
In my app I've this login screen:
Above the first test field I've an image, the configuration in Interface Builder is the follow:
Now when I tap on the UITextField they should move up otherwise in iPhone 4/4s the field will be covered by keyboard.
Now I'm using the following code:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frameView = self.view.frame;
CGRect frameImage = self.imageViewLogo.frame;
CGRect frameTextFieldUsername = self.textFieldUsername.frame;
CGRect frameTextFieldPassword = self.textFieldPassword.frame;
CGRect frameButtonLogin = self.buttonLogin.frame;
frameView.origin.y = -100;
frameImage.origin.y = -100;
frameTextFieldUsername.origin.y = -100;
frameTextFieldPassword.origin.y = -100;
frameButtonLogin.origin.y = -100;
[self.view setFrame:frameView];
[self.imageViewLogo setFrame:frameImage];
[self.textFieldUsername setFrame:frameTextFieldUsername];
[self.textFieldPassword setFrame:frameTextFieldPassword];
[self.buttonLogin setFrame:frameButtonLogin];
[UIView commitAnimations];
}
When I try to run the app in simulator or on a real device the view scrolls up of 100 but the image, the text fields and button doesn't scrolls up... I thought that the problem depend on the constraints, can you help me to fix this issue?
Thank you
The way in which you are trying to do this will get you in trouble. As you are giving hardcoded values of frame.
Try to use keyboard avoiding library it's the better and safer way of doing it.
-(void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frameView = self.view.frame;
CGRect frameImage = self.imageViewLogo.frame;
CGRect frameTextFieldUsername = self.textFieldUsername.frame;
CGRect frameTextFieldPassword = self.textFieldPassword.frame;
CGRect frameButtonLogin = self.buttonLogin.frame;
frameView.origin.y = -100;
// no need of changing frames of TextFields inside the View, Just change the y-padding of View
[self.view setFrame:frameView];
[UIView commitAnimations];
}
reduce the y-padding to -120 and check
Hope this helps thanks
If your views are set up to use AutoLayout, changing frame will do nothing.
You should subscribe to UIKeyboardWillChangeFrameNotification and perform your changes there. In case of constraints you would update the constrains constants here and the call -setNeedsUpdateConstraints on the superview.
You have to figure out if the keyboards is appearing or disappearing at all if you want to support external keyboard.
Otherwise you can listen for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification
For auto up the textFields while keyboard comes not need to use the thirdParty Classes.
Create a static tableView and design each textFields and button in each static cells.
TableView automatically handle the auto up textFields while keyboard comes.
Hi the simple and easy trick for doing it is :-
Take outlet of top constraint of username or email id textfield in your class and on textfield did begin editing delegate decrease the constraint's constant value so it will goes up when u select the textfield and at textField did end editing delegate again set constraint's constant value to previous one so it will reset on previous position.
eg:-Assuming you set Top Constraint value in Storyboard is 150
-(void)textFieldDidBeginEditing:(UITextField *)textField {
_topConstraint.constant = 10.00;
[UIView animateWithDuration:0.5f animations:^{
[self.view layoutIfNeeded];
}];
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
_topConstraint.constant = 150.00;
[UIView animateWithDuration:0.5f animations:^{
[self.view layoutIfNeeded];
}];
}
Hope it will help you.
I've been searching around SO and have found some related posts, but none that have (yet) solved my problem.
I have a view setup in my storyboard, with a constraint hooked up through an IBOulet. Upon a certain action, the view should move up (or down to it's initial position). For the life of me, I cannot get it to work properly. Prior to autolayout, I ran this bit of code:
- (void)animateStarBackground:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
myView:(UIView *)myView
xPos:(float)xPos
yPos:(float)yPos {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationDelay:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:self];
myView.center = CGPointMake(xPos, yPos);
[UIView commitAnimations];
}
It used to work great, but anyway... we all know that this doesn't work in Autolayout anymore. So I changed it to the following:
-(void)animateButton:(UIView *)myView {
[UIView animateWithDuration:8.0f animations:^{
_viewConstA.constant = 45.0;
[myView layoutIfNeeded];
}];
}
When the action occurs, instead of starting in it's initial position as set in the Storyboard, it starts off as a 1x1 pixel view in the top left hand corner and animates downward into it's final resting place (instead of moving up 15 pixels as I had intended it to).
Now, if I take out the [myView layoutIfNeeded]; portion, the action positions the view in exactly the right place... BUT it doesn't animate there. It's just instantly there as the view appears.
The first screen grab is the initial location.
2nd grab is what's supposed to be the views final resting place.
3rd is the view animating from the wrong spot and direction.
Thoughts / comments? What the heck am I doing wrong? I thought this would be so easy... I've got to be missing something obvious.
When I call the following block-based animation from viewDidLoad, it animates the frame from CGRectZero to the final location. But if I call this from viewDidAppear, it works just as expected.
- (void)animateMovementByConstraint
{
[UIView animateWithDuration:0.5
animations:^{
self.topLayoutConstraint.constant = 100;
[self.view layoutIfNeeded];
}];
}
(In this example, topLayoutConstraint is an IBOutlet that I defined in Interface Builder for the top vertical constraint on the control that I wanted to animate.)
With auto layout, since I've started initiating my animations in viewDidAppear, I haven't had any problems.
I have two UIImageView filling the view controller, the first is filling the top half, and the second for the bottom half. I set them directly in the storyboard file.
In the viewDidLoad method, i am setting code in order to perform animation for the two UIImageView, so that it will look like a basket which gets opened (the first UIImageView moved to the top until it gets out of the view, and the second UIImageView moved to the bottom of the view until it gets out of the view).
This is my code so far:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGRect basketTopFrame = self.basketTop.frame;
basketTopFrame.origin.y = -basketTopFrame.size.height;
CGRect basketBottomFrame = self.basketBottom.frame;
basketBottomFrame.origin.y = self.view.bounds.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.basketTop.frame = basketTopFrame;
self.basketBottom.frame = basketBottomFrame;
[UIView commitAnimations];
}
But the behavior is different than i was expecting, the top frame is not moving, and the bottom frame is animated from top left to bottom (origin position, and not moving out of the view).
This is UIImageViews position as i set in the storyboard:
This is the UIImageViews when i launch the app:
And this is the UIImageViews when the app finish the animation(viewDidLoad):
Please note that this code works in Xcode 4.2, but since upgrading to Xcode 4.5 and using Storyboard, i begin getting this issue. Thanx in advance.
You may have auto layout enabled on your storyboard. In this case the view components will not have a valid frame value at viewDidLoad, so your code won't work.
You can disable auto layout by selecting the file inspector in the storyboard and unchecking "Use Autolayout".
In any case, that is the wrong method to be starting an animation from. Try moving the code to viewDidAppear.
Once you have "AutoLayout" turned off and if you are targeting IOS 4 and later than block based UIView animation is recommended by Apple as it simplifies the process and you can do things in one line. Please check UIView Reference for further information.
In your case , whether you plan to do the animation in ViewDidLoad / ViewWillAppear, it can be done in the following way using block based animation:
CGRect basketTopFrame = self.boxTop.frame;
CGRect basketBottomFrame = self.boxBottom.frame;
[UIView animateWithDuration: 0.5 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.boxTop setFrame:CGRectMake(basketTopFrame.origin.x, -basketTopFrame.size.height, basketTopFrame.size.width, basketTopFrame.size.height)];
[self.boxBottom setFrame:CGRectMake(basketBottomFrame.origin.x, self.view.bounds.size.height, basketBottomFrame.size.width, basketBottomFrame.size.height)];
} completion:^(BOOL finished) {
// TODO : Do any additional stuffs.
}];
I'm using the code below to animate UITableView height change in response to keyboard appearing/disappearing.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
[UIView setAnimationBeginsFromCurrentState:YES];
CGRect tableFrame = self.messagesTableView.frame;
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
tableFrame.size.height -= kKeyboardHeightPortrait;
} else {
tableFrame.size.height -= kKeyboardHeightLandscape;
}
self.messagesTableView.frame = tableFrame;
[UIView commitAnimations];
It's working as expected except for one thing, as soon as the animation starts, the cells in the upper half of the table view disappear.
Before animation starts:
After animation starts:
It's also worth mentioning that the table view is an instance of UIBubbleTableView
I've tried to reproduce your issue, but could not. In any case I have just submitted extended example of UIBubbleTableView into github which does the thing you are trying to do and everything seems good so far, take a look at the latest commit (https://github.com/AlexBarinov/UIBubbleTableView/commit/bc0dc5b151241c4ae476c894e23800156e9709a8)
If you still have questions feel free to add issues into github tracker or contact me to provide the source you think does not work for investigation. Email is available in github profile.
That's because you never initialize those cells.