Exclude view from UIAnimation - uitableview

I have made a "pull-to-refresh" and when finished updating the inset is removed using animation block. However I'm getting unwanted animations in the custom uitableviewcell, see movie:
https://www.youtube.com/watch?v=rZcEBm_fTUc&feature=youtu.be
Watch carefully at the bottom. I found this:
How can I exclude a piece of code inside a core animation block from being animated?
But don't know how to use it, here is the code that I'm using:
id animation = ^{
//Remove the contentinset
[self.tableView setContentInset:refreshView.initialInset];
};
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionAllowUserInteraction |UIViewAnimationOptionBeginFromCurrentState
animations:animation
completion:nil];
[refreshView endAnimation];
}
Thankful for any help on this matter!

I was not reusing my UITableViewCells correctly. Before i removed all subviews from the cell and added them again, which is the wrong way to do it.
By using "reuseIdentifier" for my different UITableViewCells and only instantiating the UILabels and UIButtons once the problem disappeared (along with a lot of other problems)

Related

Stop a UITableView from automatically scrolling

I have a UITableView that I'm autoscrolling with setContentOffset. Like so:
CGFloat point = self.table.tblMinutes.contentSize.height - self.table.tblMinutes.bounds.size.height;
[self.table.tblMinutes setContentOffset:CGPointMake(0, point) animated:false];
[self.table.tblMinutes layoutIfNeeded];
[UIView animateWithDuration:20.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[self.table.tblMinutes setContentOffset:CGPointMake(0, point - 500) animated:false];
} completion:nil];
What I want to achieve is for the scrolling to smoothly slow down and stop. I haven't been able to achieve that.
Calling [self.table.tblMinutes.layer removeAllAnimations] stops the animation, but moves the contentOffset for some reason, not achieving what I want.
I tried using the UIViewAnimationOptionBeginFromCurrentState option in a animation but that did nothing.
Any suggestions?
This is a subset of the classic problem of interrupting an existing animation and replacing it with a different animation.
The problem here is that if you merely remove the existing animation, you will jump to the end of that animation.
The solution to that is to consult the presentation layer and set the layer to that position before removing the existing animation. Now you are starting from midstream and can apply another animation.
Take a look at Kyle Truscott's excellent blog post about this for UIScrollView. UITableView inherits from UIScrollView, so in theory, it should work.

UIView animation returns to origin

I have a UILabel inside of a UITableViewCell. I am trying to animate the label moving to the right when the user taps the cell. I have this code:
CGRect otherFrame = cellLabel.frame;
otherFrame.origin.x +=50;
[UIView animateWithDuration:1.0f animations:^{
cellLabel.frame = otherFrame;
}];
The odd thing that's happening is that the label is jumping 50 pixels to the left and animating back to its origin (where it was before the action began).
I actually had this working earlier in the week and didn't have any trouble with it, and after scouring through the revision history, I can't figure out where I've gone wrong. I must be missing something stupid.
EDIT:
Based on the answer from Jakub, I found that this works:
[UIView animateWithDuration:0.01f animations:^{}
completion:^(BOOL finished)
{
CGRect otherFrame = cellLabel.frame;
otherFrame.origin.x += 50;
[UIView animateWithDuration:1.0f animations:^{
cellLabel.frame = otherFrame;
}];
}];
Oddly, if I move all of the logic into a completion handler that performs a new animation after the first one completes (without the first actually doing anything), everything animates properly. This is super hacky, and I'm not at all happy with it.
Can anyone think of what would cause the initial animation to move the frame to the negative offset of the intended destination, only to animate it back to its origin, and why triggering a new animation as the completion handler of an empty animation would work?
EDIT 2:
I am going to mark Duncan's answer as the right one because it pointed me in the right direction, but I am still baffled why/how these symptoms can happen:
The animation moves the frame to the negative offset of the
destination, then animates it back to the origin (rather than from
the origin to the destination)
Running an empty animation block but adding another animation to the first block's completion handler animates correctly
Info for the attempted answers:
I have to use auto layout for the project, and as far as I know, I
can't disable it for a single view
I am not putting anything onto a background thread. I didn't try specifically dispatching to the main thread, but I think I was already there. Isn't all visible UI always on the main thread? It was animating, just not as expected.
The reason I didn't go the route of changing constraints to begin with is that I am using prototype cells and IB doesn't let you create IBOutlets from prototype cells. There's a bit of work to walk a constraint list and detect a specific one, so I left the constraints blank and tried to animate the frame (and as I said, it was working earlier in the week -- and still worked when animating from an animation block's completion handler).
So the final solution was to add constraints to the container cell (the important one here being the leading), then to animate, I had to find the constraint:
NSLayoutConstraint *titleLeadingConstraint = nil;
for( NSLayoutConstraint *constraint in cellLabel.superview.constraints )
{
if( constraint.firstItem == cellLabel && constraint.firstAttribute == NSLayoutAttributeLeading )
{
titleLeadingConstraint = constraint;
}
}
Then set the constraint constant:
titleLeadingConstraint.constant = 55.0;
Then set the animation block:
[UIView animateWithDuration:1.0f animations:^{
[self.view layoutIfNeeded];
}];
This solution should be more future proof (and robust, reliable and stable) than moving the frame, but it turned out to be a fair amount of work in discovery.
Do you have auto layout set in your storyboard or XIB by mistake? (It is on by default). If so you either need to turn AutoLayout off or animate a constraint rather than manipulating your view's frame.
Where are you calling this code?
Try calling UIView animateWithDuration:... method on the main thread, in a
dispatch_async(dispatch_get_main_queue(), ^{
// Your animation here
});
If this method is not executed on the main thread, it usually jumps to the final stage of the animation.
You should reset the origin after animation.

In iOS 7, is it possible to have a view slide down from a tableview section header?

I have been researching this for the better part of a day now, and I am coming to the conclusion that it may not be possible. Here's what I am trying to do. I have a TableViewController, and in that I have a table view with one section. I have set the section header to contain a UIView, and I am leaving the default "sticky" behavior so the section header doesn't scroll with the rows. I want to introduce a button on the section header that when tapped will cause a second TableView to slide DOWN from the section header. Basically, I want similar functionality to the notifications window, but I want it to slide out/down from the table's section header.
Thus far, my best attempt involves redrawing the section header, and then calling [self.tableView reloadData], which results in a twitchy effect and the second tableViewController doesn't display correctly. My next thought is to actually use the second TableView as the UIView in the section header, and only display the footer of the second TableView until the user taps the header. Even if I do this, though, I still can't figure out how to create the slide-down transition.
Any help or ideas on this will be greatly appreciated.
To slide a View down from above, I finally settled on this code:
-(void) openView
{
[UIView animateWithDuration:1.0
animations:^{
loadingView.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);
}
completion:^(BOOL finished){
}];
}
-(void) closeView
{
[UIView animateWithDuration:1.0
animations:^{
loadingView.frame = CGRectMake(0,-40-self.view.frame.size.height,self.view.frame.size.width,self.view.frame.size.height);
}
completion:^(BOOL finished){
}];
}
When closing the view I start with -40 on the y axis because I needed an offset for my work. If you use this code you may need to play around with the values to get what you need. I hope this can point someone else in the right direction for a solution to their specific problem.

UIScrollView Jerky Scrolling

I have a big scroll view. I just wish to scroll around the scroll view with fixed steps on every button press. However when I write the following code the scroll view scrolling is very jaggy. Can someone explain why?
CGPoint lstructCurrentPoint = self.objScrollView.contentOffset;
lstructCurrentPoint.x += 400;
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationOptionCurveLinear
animations:^{
[self.objScrollView scrollRectToVisible:CGRectMake(lstructCurrentPoint.x,
lstructCurrentPoint.y,
self.objScrollView.bounds.size.width,
self.objScrollView.bounds.size.height)
animated:NO];
} completion:^(BOOL finished)
{
}];
I do not use the animated:Yes arguement because I need custom scroll speeds between the different contentOffsets.
when you update your scroolview content frame while scrolling with an animation is like you try to update something that is in the past that is already changed... (probably is not the best explanation :D )
try with this in your animation option:
options:UIViewAnimationOptionCurveLinear|UIViewAnimationOptionBeginFromCurrentState
Why don't you just try using
[self.objScrollView scrollRectToVisible:CGRectMake(lstructCurrentPoint.x, lstructCurrentPoint.y,self.objScrollView.bounds.size.width,self.objScrollView.bounds.size.height) animated:YES];
instead of using this within UIView animation function.
Try to use
[self.objScrollView setContentOffset: CGPointMame(lstructCurrentPoint.x, lstructCurrentPoint.y) animated: YES];
instead of scrollRectToVisible.
scrollRectToVisible animated is an animation by itself.
With your current code, you are trying to animate the animation.
Hence it is jerky.
Just use to scroll the rect to visible:
[self.objScrollView scrollRectToVisible:CGRectMake(lstructCurrentPoint.x,lstructCurrentPoint.y,self.objScrollView.bounds.size.width,self.objScrollView.bounds.size.height) animated:YES];
No one can properly answer your question without knowing what content you have in the scrollView.
However, you can find out what is causing this yourself.
Profile the app on your device. This will open Instruments. Select the Core Animation tool.
When the app is running scroll the view so that instruments captures the data.
Now the Time Profiler section will tell you exactly what is taking a long time. Fix this and you'll have smooth scrolling.

Leveled UITableView without NavigationController

I have data structured as a tree (and showed in UITableView) and I would like to show it the way it is usually done using UINavigationController and pushing child views on to the stack. The problem is that my UITableView (in an iPad app) takes only 1/6 of the screen (there is a UINavigationController that handles other fullscreen iPad screens in this app, so using NavigationController to control the levels of table is the good way).
Is there a simple way to get a good visual effect of changing the levels of TableView without using NavigationController? Right now I just change the data source and reload data, but that does something like a flicker on the screen (the user can't really see, that the structure of the data is tree-like).
I thought of creating a few TableViews and then just animating the resize (from full width to 0 the TableView that we are leaving, and from 0 to width at the same time of the another one) of a table just to make something like segue effect - but I am not sure if this is a good approach.
You can use reloadSections:withRowAnimation: with UITableViewRowAnimationLeft and UITableViewRowAnimationRight instead of a default reloadData. This will look like the push you are looking for.
Reference: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/reloadSections:withRowAnimation:
You can try this code (after you set the proper values:))
__block CGRect frame = tableView.frame;
[UIView animateWithDuration:0.5 animations:^{
frame.origin.x -=tableView.frame.size.width;
} completion:^(BOOL finished) {
frame.origin.x = yourViewThatContainsTheTable.frame.size.width
tableView.frame = frame;
[tableView reloadData];
[UIView animateWithDuration:0.3 animations:^{
frame.origin.x = 0;
tableView.frame = frame;
}];
}];
Basically if you are using subclasses of UIView you can use [UIView animateWith...] methods to perform simple animations or you can use CAAnimations/CABasicAnimation/CAAnimationGroup/CAKeyframeAnimation for more complex animations on subclasses of UIView.
If you want a custom transition for a UIViewController you can use CATransition.

Resources