核心动画和变换,如 ZoomRectToVisible

发布于 2024-09-06 13:57:23 字数 3949 浏览 7 评论 0原文

我正在尝试获得类似于 UIScrollview 的 zoomRectToVisible 方法的效果。 但我的方法应该能够在缩放时将特定的矩形置于图层的中心,并且应该能够在设备方向更改后重新调整。

我正在尝试编写一个像 Marvel-comic 应用程序一样的软件,并且需要一个在页面中呈现每个面板的视图。

对于我的实现,我使用 CALayer 和 Core Animation 通过 CATransform3D 转换获得所需的效果。我的问题是,我无法使缩放的矩形/面板居中。

我的实现的结构如下所示:我有一个 UIScrollview 的子类,其中添加了一个 UIView 作为子视图。 UIView 在其 CALayer.contents 中包含图像/页面,我使用核心动画来获得缩放和居中效果。每个面板上的缩放效果均正常工作,但居中位置已关闭。我无法计算正确的居中平移变换。

我的效果实现代码是这样的:

- (void) zoomToRect:(CGRect)rect animated:(BOOL)animated {
    CGSize scrollViewSize = self.bounds.size;

    // get the current panel boundingbox
    CGRect panelboundingBox = CGPathGetBoundingBox([comicPage panelAtIndex:currentPanel]);

    // compute zoomfactor depending on the longer dimension of the panelboundingBox size
    CGFloat zoomFactor = (panelboundingBox.size.height > panelboundingBox.size.width) ? scrollViewSize.height/panelboundingBox.size.height : scrollViewSize.width/panelboundingBox.size.width;

    CGFloat translateX = scrollViewSize.width/2 - (panelboundingBox.origin.x/2 + panelboundingBox.size.width/2);
    CGFloat translateY = scrollViewSize.height/2 - (panelboundingBox.size.height/2 - panelboundingBox.origin.y);

    // move anchorPoint to panelboundingBox center
    CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));


    // create the nessesary transformations
    CATransform3D translateMatrix = CATransform3DMakeTranslation(translateX, -translateY, 1);
    CATransform3D scaleMatrix = CATransform3DMakeScale(zoomFactor, zoomFactor, 1);

    // create respective core animation for transformation
    CABasicAnimation *zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    zoomAnimation.fromValue =  (id) [NSValue valueWithCATransform3D:contentViewLayer.transform];
    zoomAnimation.toValue = (id) [NSValue valueWithCATransform3D:CATransform3DConcat(scaleMatrix, translateMatrix)];
    zoomAnimation.removedOnCompletion = YES;
    zoomAnimation.duration = duration;

    // create respective core animation for anchorpoint movement
    CABasicAnimation *anchorAnimatione = [CABasicAnimation animationWithKeyPath:@"anchorPoint"];
    anchorAnimatione.fromValue = (id)[NSValue valueWithCGPoint:contentViewLayer.anchorPoint];
    anchorAnimatione.toValue = (id) [NSValue valueWithCGPoint:anchor];
    anchorAnimatione.removedOnCompletion = YES;
    anchorAnimatione.duration = duration;

    // put them into an animation group
    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = [NSArray arrayWithObjects:zoomAnimation, anchorAnimatione, nil] ;

    /////////////

    NSLog(@"scrollViewBounds (w = %f, h = %f)", self.frame.size.width, self.frame.size.height);
    NSLog(@"panelBounds (x = %f, y = %f, w = %f, h = %f)", panelboundingBox.origin.x, panelboundingBox.origin.y, panelboundingBox.size.width, panelboundingBox.size.height);
    NSLog(@"zoomfactor: %f", zoomFactor);
    NSLog(@"translateX: %f, translateY: %f", translateX, translateY);
    NSLog(@"anchorPoint (x = %f, y = %f)", anchor.x, anchor.y);

    /////////////

    // add animation group to layer 
    [contentViewLayer addAnimation:group forKey:@"zoomAnimation"];

    // trigger respective animations
    contentViewLayer.anchorPoint = anchor;
    contentViewLayer.transform = CATransform3DConcat(scaleMatrix, translateMatrix);
}

所以视图需要以下几点:

  1. 它应该能够根据当前设备方向缩放和居中图层/视图的矩形/面板。 (UIScrollview 的 zoomRectToVisible 不会使矩形居中)
  2. 如果有必要(设备方向更改或面板需要旋转),缩放面板/矩形应该能够旋转
  3. 动画的持续时间取决于用户的偏好。 (我不知道是否可以更改 UIScrollView 的 ZoomRectToVisible 的默认动画持续时间?)

这些点就是我覆盖 UIScrollView 的 ZoomRectToVisible 方法的原因。

所以我必须知道如何正确计算转换的平移参数。

我希望有人能指导我获得正确的参数。

I'm trying to get an effect like the zoomRectToVisible-method of UIScrollview.
But my method should be able to center the particular rect in the layer while zooming and it should be able to re-adjust after the device orientation changed.

I'm trying to write a software like the marvel-comic app and need a view that presents each panel in a page.

For my implementation I'm using CALayer and Core Animation to get the desired effect with CATransform3D-transformations. My problem is, I'm not able to get the zoomed rect/panel centered.

the structure of my implementation looks like this: I have a subclass of UIScrollview with a UIView added as subview. The UIView contains the image/page in it's CALayer.contents and I use core animations to get the zooming and centering effect. The zoom effect on each panel works correcty but the centering is off. I'm not able to compute the correct translate-transformation for centering.

My code for the implementation of the effect is like this:

- (void) zoomToRect:(CGRect)rect animated:(BOOL)animated {
    CGSize scrollViewSize = self.bounds.size;

    // get the current panel boundingbox
    CGRect panelboundingBox = CGPathGetBoundingBox([comicPage panelAtIndex:currentPanel]);

    // compute zoomfactor depending on the longer dimension of the panelboundingBox size
    CGFloat zoomFactor = (panelboundingBox.size.height > panelboundingBox.size.width) ? scrollViewSize.height/panelboundingBox.size.height : scrollViewSize.width/panelboundingBox.size.width;

    CGFloat translateX = scrollViewSize.width/2 - (panelboundingBox.origin.x/2 + panelboundingBox.size.width/2);
    CGFloat translateY = scrollViewSize.height/2 - (panelboundingBox.size.height/2 - panelboundingBox.origin.y);

    // move anchorPoint to panelboundingBox center
    CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));


    // create the nessesary transformations
    CATransform3D translateMatrix = CATransform3DMakeTranslation(translateX, -translateY, 1);
    CATransform3D scaleMatrix = CATransform3DMakeScale(zoomFactor, zoomFactor, 1);

    // create respective core animation for transformation
    CABasicAnimation *zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    zoomAnimation.fromValue =  (id) [NSValue valueWithCATransform3D:contentViewLayer.transform];
    zoomAnimation.toValue = (id) [NSValue valueWithCATransform3D:CATransform3DConcat(scaleMatrix, translateMatrix)];
    zoomAnimation.removedOnCompletion = YES;
    zoomAnimation.duration = duration;

    // create respective core animation for anchorpoint movement
    CABasicAnimation *anchorAnimatione = [CABasicAnimation animationWithKeyPath:@"anchorPoint"];
    anchorAnimatione.fromValue = (id)[NSValue valueWithCGPoint:contentViewLayer.anchorPoint];
    anchorAnimatione.toValue = (id) [NSValue valueWithCGPoint:anchor];
    anchorAnimatione.removedOnCompletion = YES;
    anchorAnimatione.duration = duration;

    // put them into an animation group
    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = [NSArray arrayWithObjects:zoomAnimation, anchorAnimatione, nil] ;

    /////////////

    NSLog(@"scrollViewBounds (w = %f, h = %f)", self.frame.size.width, self.frame.size.height);
    NSLog(@"panelBounds (x = %f, y = %f, w = %f, h = %f)", panelboundingBox.origin.x, panelboundingBox.origin.y, panelboundingBox.size.width, panelboundingBox.size.height);
    NSLog(@"zoomfactor: %f", zoomFactor);
    NSLog(@"translateX: %f, translateY: %f", translateX, translateY);
    NSLog(@"anchorPoint (x = %f, y = %f)", anchor.x, anchor.y);

    /////////////

    // add animation group to layer 
    [contentViewLayer addAnimation:group forKey:@"zoomAnimation"];

    // trigger respective animations
    contentViewLayer.anchorPoint = anchor;
    contentViewLayer.transform = CATransform3DConcat(scaleMatrix, translateMatrix);
}

So the view requires the following points:

  1. it should be able to zoom and center a rect/panel of the layer/view depending on the current device orientation. (zoomRectToVisible of UIScrollview does not center the rect)
  2. if nessesary (either device orientation changed or panel requires rotation) the zoomed panel/rect should be able to rotate
  3. the duration of the animation is depending on user preference. (I don't know whether I can change the default animation duration of zoomRectToVisible of UIScrollView ?)

Those points are the reason why I overwrite the zoomRectToVisible-method of UIScrollView.

So I have to know how I can correctly compute the translation parameters for the transformation.

I hope someone can guide me to get the correct parameters.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

魂归处 2024-09-13 13:57:23

浏览一下你的代码,这一行可能不会像你想象的那样被计算:

CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));

你可能会因为开头的 1/ 而得到 0。 C 会在除法之前进行乘法,得到的值 <1 - 可能不是您想要的。请参阅

您可能会发现分解计算更有用,这样您就知道它的工作原理正确的顺序(只需使用一些临时变量) - 相信我,这将极大地帮助您的代码稍后更易于阅读(和调试)。或者您可以使用更多括号...

希望这会有所帮助。

Just skimmed over your code and this line is probably not being calculated as you think:

CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));

You're likely to get 0 because of the 1/ at the start. C will do your multiplication before this division, resulting in values <1 - probably not what you're after. See this

You might find it more useful to breakdown your calculation so you know it's working in the right order (just use some temporary variables) - believe me it will help enormously in making your code easier to read (and debug) later. Or you could just use more brackets...

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文