Content Offset animation broken
Asked Answered
L

4

6

I have an animation which is kicked off when a gesture recogniser (double tap) fires:

[UIView animateWithDuration:0.3 animations:^{
  _scrollView.contentOffset              = CGPointMake(x, y);
  _scrollViewContentView.frame           = someFrame;
  _scrollViewContentView.layer.transform = 
       CATransform3DMakeScale(1.f/_zoomScale, 1.f/_zoomScale, 1.f);            
}];

It's working nice except in one case : if scrollViewWillBeginDecelerating delegate method is not called before animation execution (just by dragging hardly my scrollview).

I just have scrollViewDidEndDragging method called.I can wait 20 sec and then play my animation. It'll play correctly except for my contentOffset.

The delegate methods themselves do nothing, they were only added to see where the problem might be.

I have no idea why.

Edit : here's a video of my problem. Phase 1 : scroll with deceleration and phase 2 without. Look a the final position. Phase 1 is correct but not phase

Laminated answered 5/3, 2014 at 14:30 Comment(13)
Are you saying that sometimes scrollViewWillBeginDecelerating is not called?Coterminous
No that's normal. I directly stop my scrolling so it won't have a decelerating effect. So when I do that my animation is broken. But I my gesture have decelerating implication it works. Don't know if I clear ...Laminated
Please can you update your question to show where and when you are calling this animation?Groenendael
I meant which methods you call it from, but the video does help!Groenendael
I scroll and after (it can be 2 seconds or 10 min) I launch my animation block from a gesture (UITapGesture double tap).Laminated
Alright, cool. The video does help. However can we see a few snippets of code. Particularly your UIScrollDelegate methods?Abroad
Yep because there's nothing inside them. I just set my delegate to see where my problem wasLaminated
I've updated your question based on your comments. The fact that you were calling the animation from a gesture recogniser was important. If I've got anything wrong, please re-edit.Groenendael
Ok thx. SO you think it comes from gesture ?Laminated
In my understanding from you video, the view has a red bg is the _scrollViewContentView.And the scrollView is the black view, am I right?Broddy
@StevenJiang Yes that's rightLaminated
@Laminated And your goal is to make the scrollView zoomed and animated to a position that left-center in the screen?And could you share your sample project in the video?Broddy
@StevenJiang I can't :/ And yes that's my goalLaminated
A
1

try:

[_scrollView setContentOffSet:CGPointMake(x, y) animated:YES];

outside of the animation block. I don't believe contentOffSet is animatable through UIView's animation block.

Edit: Instead of:

_scrollview.contentOffSet = CGPointMake(x, y);

try:

_scrollview.bounds = CGRectMake(x, y, CGRectGetWidth(scrollview.bounds), CGRectGetHeight(scrollview.bounds));
Abroad answered 8/3, 2014 at 8:30 Comment(3)
No because it works inside my block after a scroll with deceleration. Without deceleration it's broken. And even if I do that, the result would be less nice for the user (different duration because mine is a constant and setContentView:animated: is not)Laminated
Hmm, alright... What I still feel like I don't completely understand the problem you are having. But another way to animate contentOffSet is to animate bounds. What if you try the code on the edit, what happens then?Abroad
Thx but same result. Look a my video ;)Laminated
S
0

I suspect that x in this line may be causing the effect that you see:

_scrollView.contentOffset              = CGPointMake(x, y);

What's it's value? I think you should try replacing that by CGPointMake(0, y) and see if that causes the white margin to appear every time.

My reasoning is the following:

1) to create bouncing effect that doesn't go outside the scope of the image (doesn't show white background), you must have set _scrollView's contentSize.width less than the actual image size.

2) to allow some scrolling you have set the contentSize.width greater than the width of the _scrollView

3) you have centered the image within the _scrollView relatively to the size of it's contentSize

4) when animating you are probably setting frame with pre-calculated x coordinate to position the image on the left size because without that CATransform3DMakeScale would just leave the image in the center (by the way, why use CATransform3DMakeScale, when you could just change the size in the frame?)

5) in the video, when running the animation the first time, you have contentOffset.x to it's maximum value (because you drag to the left therefore increasing the content offset and scrollview bounces back to it's max content offset that doesn't go beyond content size limits)

6) in the video when running the animation for the second time, you have contentOffset.x with a smaller value because you drag to the right by decreasing it

7) when animation is finished, you still have the same content size for your scrollView and therefore the same amount of scroll available. If you have the contentOffset.x at it's maximum value then image will be more on the left, if you have contentOffset.x with less value - image will be more on the right

8) if the x in _scrollView.contentOffset = CGPointMake(x, y); is related to actual content offset prior to animation then that makes sense that the image appears more on the left in the first case and more on the right in the second case.

If I'm right then this is how you could solve it:

a) If you want the image always to appear on specific x position, make sure to set constant contentOffset in the animation.

b) Adjust the code of calculating frame (someFrame) origin according to the contentOffset that you'll be animating to (looks like now it works only with the maximum contentOffset.x).

c) If after animation you don't want the content to be scrollable, make sure to set _scrollView.contentSize = _scrollview.bounds.size; in the animation block.

Shanitashank answered 14/3, 2014 at 13:8 Comment(0)
H
-1

Perhaps try using core animation rather than UIView animations. It won't make a difference if the reason you're running into trouble is because all animations are being removed from the layer, but if it's due to -[removeAnimationForKey:@"bounds"], this might be a winner.

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.fromValue = [NSValue valueWithCGRect:_scrollView.layer.bounds];
animation.toValue = [NSValue valueWithCGRect:(CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size }];
[scrollView.layer addAnimation:animation forKey:@"myCustomScroll"];
scrollView.layer.bounds = (CGRect){ .origin = CGPointMake(x,y), .size = scrollView.layer.bounds.size };

P.S. I haven't tested the code above it's just off my head, so apologies for any silly errors.

Hamelin answered 10/3, 2014 at 6:42 Comment(2)
The key path is bounds and you're setting a point for the value, would be silly error #1 ;)Groenendael
Ah yep, my mistake. Thus the disclaimer.Hamelin
P
-1

I'm not sure I completely understand your problem (Maybe you can try to explain what you want to accomplish in this animation?). Any way, maybe try this instead of using setContentOffset:

CGRect *rect = CGRectMake(x, y, 0, 0);
[_scrollView scrollRectToVisible:rect animated:YES];
Proletarian answered 10/3, 2014 at 6:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.