Table view content jumping down when using UIRefreshControl and setting contentInset - ios

So I have standard subclass of UITableViewController with table view. Now I have set content inset to
self.tableView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
I'm also using UIRefreshControl in standard way.
self.refreshControl = [[CTRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(loadData:) forControlEvents:UIControlEventValueChanged];
All works fine and smoothly if table view contains enough data that it scrolls(so content size height is more than table view's height). When there is not enough data in table (e.g. only 2 rows) then when I start to pull down it goes smoothly and then suddenly it jumps by about 20 points down. Same thing happens when I scroll other direction. It doesn't happen when there's no refresh control or when I don't change contentInset. Any ideas? All on iOS 6.

You need to put the change of contentInset in an animation block like this...
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.tableView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
}
completion:nil];
(Typed from memory so you may have to check code completion).
This should fix your problem.

Related

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.

Resizing UIButton Width/Height (iOS) - How to resolve without disabling autolayout?

I'm trying to increase the height of a button (via animation) when another button is clicked. The issue I'm having is that instead of increasing it, it decreases it back to the starting height. After doing some searching around on Stackoverflow, it appears that the issue has to do with having autolayout enabled. I tried disabling autolayout and this is exactly the issue. I would like to know though, if there is a work around that doesn't involve disabling autolayout. Here's my code:
self.button.frame = CGRectMake(39, 39, 242, 215);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4f];
self.button.frame = CGRectMake(39, 39, 242, 315);
[UIView commitAnimations];
You do this by making an IBOutlet to a height constraint you made in IB (called heightCon in my example), and then animating its constant value,
[UIView animateWithDuration:.4 animations:^{
self.heightCon.constant = 315;
[self.view layoutIfNeeded];
}];

Animating two UIView subviews at the same time does not work

For some reason i am not able two animate two subviews postion. I have wrote the following
[self addChildViewController:self.photosViewController];
[self.photosViewController.view setFrame:CGRectMake(0, -self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:self.photosViewController.view];
[UIView animateWithDuration:1 delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[self.stepsView setFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[self.photosViewController.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
completion:^(BOOL finished) {
if (finished) {
button.tag = 0;
}
}];
self.stepsView is an IBOutlet UIView and self.photosViewController.view is an child view controllers view that has been added to the view.
With the current code only the self.PhotosViewController.view animates. However if i comment out the line where i add the child view controllers view as a subview then the self.stepsView animates correctly.
Even if i add the child view controller and its view before this method is called the same error happens.
Need help as i ran in to this a couple of months back with another app and had to do a dirty hack to get around it and now want to solve this.
Thanks
In the section on view animation in the View Programming Guide there is a specific mention of how to animate subviews.
Basically, you should use transitionWithView:duration:options:animations:completion: rather than animateWithDuration:delay:options:animations:completion:.
The first view will not be visible, because its origin.y is beyond the height of the visible view. If it was not visible when the animation starts, you will of course see nothing.
The second view is changed to fill the screen. Again, what you see depends on its initial position.

Animating UITableView resize

Im using the following code to animate the resizing of a UITableView to make way for a UIView with extra controls when the UITableView.isEditing.
[UIView animateWithDuration:3 // 0.2 but slowed down to easily see difference
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.selectControlsView setFrame:CGRectMake(0, self.tableView.frame.size.height-self.selectControlsView.frame.size.height, self.selectControlsView.frame.size.width, self.selectControlsView.frame.size.height)];
[self.tableView setFrame:CGRectMake(0, 0, self.tableView.frame.size.width, self.tableView.frame.size.height-self.selectControlsView.frame.size.height)];
}
completion:nil];
This works fine except it seems the UITableView animates faster than the UIView does (even though I adjust the UIViews frame before the UITableViews frame), causing a black flicker during the animation from the background.
Is there a way to animate the two views in tandem?
The problem was caused because the controller was a subclass of UITableViewController. I'm now subclassing UIViewController and adding the UITableView as a subview, the animation for adding the new view and resizing the UITableView now works as expected.

UIView animation while scrolling a table

I have a UITableView in an iPad, and its right half side is covered with a view.
What I want is: when the user scroll the UITableView, I want the covering view to slide (with an animation) to the right until its origin.x is at the end of the right side of the table, so the UITableView is clear to see (just like in the Twitter app for iPad).
The problem is: You can scroll the UITableView and animate a view at the same time. When I start scrolling, I use didStartDraging and even DidScroll to create a [UIView animate...] method, but this method stuck my scrolling.
I tired with block animation. I tried with Gestures. I tried with CABasicAnimation, and it goes quite OK, but somehow all the UISubview "Touch area" in my sliding view stay at the old place (what I mean is that the view gets its new frame, but I can scroll a UIScrollView, which is a UISubview of my view, even when my finger is out of the superviews frame S-:, even that there is no view at that point on screen.)
Any thoughts how can I make the animation without damaging the scroll of the table? (and I heard about the timer in the K and the runloop common modes. Not so helping)
Thanks.
scrollview Delegate methods will be invoked for tableView also ............
you can use following code it worked for me and hope will work for you also.......
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[UIView animateWithDuration:0.3 animations:^{
[scrollView setFrame:CGRectMake(50, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height)];
}];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[UIView animateWithDuration:0.3 animations:^{
[scrollView setFrame:CGRectMake(100, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height)];
}];
}
set x position of scrollView(tableView) as your requirement......
Have a happy coding....

Resources