1

我试图得到像zoomRectToVisible-UIScrollview方法的效果。 但是我的方法应该能够在缩放时在图层中居中放置特定的矩形,并且在设备方向改变后它应该能够重新调整。Core Animation and Transformation like zoomRectToVisible

我正在尝试编写一个像marvel-comic app这样的软件,并且需要一个呈现页面中每个面板的视图。

对于我的实现,我使用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不居中RECT)
  2. 如果所必要的(或者设备的方向改变或面板需要旋转)缩放面板/ RECT应该能够
  3. 动画的持续时间取决于用户偏好旋转。 (我不知道是否可以更改UIScrollView的zoomRectToVisible的默认动画持续时间?)

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

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

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

回答

-1

只是掠过你的代码,此行可能是不被计算为你想:

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 - 可能不是你所追求的。请参阅this

您可能会发现将计算细分为更有用,因此您知道它的运行顺序正确(只是使用一些临时变量) - 相信我会极大地帮助您的代码更易于读取(和调试)后来。或者你可以使用更多的支架...

希望这会有所帮助。

+0

'*'和'/'具有相同的运算符优先级(请参阅您的链接)。这实际上意味着它们将从(从逻辑上)从左到右执行。 – 2017-04-03 10:49:28