内容偏移动画损坏

Posted

技术标签:

【中文标题】内容偏移动画损坏【英文标题】:Content Offset animation broken 【发布时间】:2014-03-05 14:30:30 【问题描述】:

我有一个在手势识别器(双击)触发时启动的动画:

[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);            
];

它工作得很好,除了在一种情况下:如果在动画执行之前没有调用scrollViewWillBeginDecelerating 委托方法(只是通过几乎不拖动我的滚动视图)。

我刚刚调用了scrollViewDidEndDragging 方法。我可以等待20 秒然后播放我的动画。除了我的contentOffset 之外,它将正常播放。

委托方法本身什么都不做,它们只是被添加来看看问题可能出在哪里。

我不知道为什么。

编辑:这是我的问题的video。第 1 阶段:减速滚动,第 2 阶段没有。看看最后的位置。阶段1是正确的但不是阶段

【问题讨论】:

你是说有时不调用scrollViewWillBeginDecelerating? 不,这很正常。我直接停止滚动,因此不会产生减速效果。所以当我这样做时,我的动画就坏了。但我的手势有减速暗示它有效。不知道我是否清除... 请您更新您的问题以显示您在何时何地调用此动画? 我的意思是你调用它的方法,但视频确实有帮助! 我滚动并在之后(可能是 2 秒或 10 分钟)我从一个手势(UITapGesture 双击)启动我的动画块。 【参考方案1】:

尝试:

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

在动画块之外。我不相信 contentOffSet 可以通过 UIView 的动画块设置动画。

编辑: 而不是:

_scrollview.contentOffSet = CGPointMake(x, y);

尝试:

_scrollview.bounds = CGRectMake(x, y, CGRectGetWidth(scrollview.bounds), CGRectGetHeight(scrollview.bounds));

【讨论】:

不,因为它在减速滚动后在我的块内工作。没有减速就坏了。即使我这样做,结果对用户来说也不会那么好(不同的持续时间,因为我的是一个常量,而 setContentView:animated: 不是) 嗯,好吧...我仍然觉得我不完全理解您遇到的问题。但是为 contentOffSet 设置动画的另一种方法是为边界设置动画。如果你在编辑时尝试代码,会发生什么? 谢谢,但结果相同。看我的视频;)【参考方案2】:

我怀疑这行中的 x 可能会导致您看到的效果:

_scrollView.contentOffset              = CGPointMake(x, y);

它有什么价值?我认为您应该尝试用 CGPointMake(0, y) 替换它,看看是否会导致每次出现白边。

我的理由如下:

1) 要创建不超出图像范围(不显示白色背景)的弹跳效果,您必须将_scrollViewcontentSize.width 设置为小于实际图像大小。

2) 要允许滚动,您将contentSize.width 设置为大于_scrollView 的宽度

3) 您已将_scrollView 中的图像相对于contentSize 的大小居中

4) 制作动画时,您可能正在使用预先计算的 x 坐标设置框架以将图像定位在左侧尺寸上,因为没有那个 CATransform3DMakeScale 只会将图像留在中心(顺便说一下,为什么使用 CATransform3DMakeScale ,你什么时候可以改变框架的大小?)

5) 在视频中,第一次运行动画时,您将 contentOffset.x 设置为最大值(因为您向左拖动,因此增加了内容偏移量,并且滚动视图反弹回它的最大内容偏移量) t 超出内容大小限制)

6) 在视频中第二次运行动画时,contentOffset.x 的值较小,因为您通过减小它向右拖动

7) 动画完成后,scrollView 的内容大小仍然相同,因此可用滚动量相同。如果 contentOffset.x 的最大值为最大值,则左侧的图像会更多,如果 contentOffset.x 的值较小 - 右侧的图像会更多

8) 如果_scrollView.contentOffset = CGPointMake(x, y); 中的 x 与动画之前的实际内容偏移有关,那么在第一种情况下图像更多出现在左侧,而在第二种情况下更多出现在右侧,这是有道理的。

如果我是对的,那么这就是你可以解决的方法

a) 如果您希望图像始终出现在特定的 x 位置,请确保在动画中设置常量 contentOffset。

b) 根据您要制作动画的 contentOffset 调整计算帧 (someFrame) 原点的代码(看起来现在它只适用于最大 contentOffset.x)。

c) 如果在动画之后您不希望内容可滚动,请确保在动画块中设置_scrollView.contentSize = _scrollview.bounds.size;

【讨论】:

【参考方案3】:

我不确定我是否完全理解你的问题(也许你可以试着解释一下你想在这个动画中完成什么?)。无论如何,也许试试这个而不是使用setContentOffset

CGRect *rect = CGRectMake(x, y, 0, 0);
[_scrollView scrollRectToVisible:rect animated:YES];

【讨论】:

【参考方案4】:

也许尝试使用核心动画而不是 UIView 动画。如果您遇到麻烦的原因是因为所有动画都从图层中删除,那不会有什么不同,但如果是由于-[removeAnimationForKey:@"bounds"],这可能是赢家。

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 ;

附:我还没有测试上面的代码,这只是我的想法,所以对任何愚蠢的错误表示歉意。

【讨论】:

关键路径是 bounds 并且您正在为该值设置一个点,这将是愚蠢的错误 #1 ;) 啊,是的,我的错误。因此免责声明。

以上是关于内容偏移动画损坏的主要内容,如果未能解决你的问题,请参考以下文章

多个动画的动画偏移

使用动画移动时获取元素的偏移量

为移动目标 lat/lng 和缩放级别的动画偏移地图片段的中心

UIScrollview 动画取决于内容偏移

wpf中让控件进行移动的动画

在动画偏移时动画删除/添加 SwiftUI 视图