你如何翻译和缩放视图没有相互冲突的转换 (translate nena)

我需要翻译和缩放 UIView 从屏幕的中心到右上角。

我需要翻译和缩放 UIView 从屏幕的中心到右上角。

 _____________________________
|                            |
|                            |
|         _________          |
|        |         |         |    START
|        |         |         |
|        |_________|         |
|                            |
|                            |
|____________________________|
 _____________________________
|                       __   |
|                      |__|  |
|                            |
|                            |    END
|                            |
|                            |
|                            |
|                            |
|____________________________|

我验证了我个人对比例和平移的计算是准确的。但是一旦它们放在一起,它们就会相互冲突。下面的代码使视图最终太靠近中心。

CGFloat finalPadding = 10.0f;
CGFloat finalScale = 46.0f / 170.0f;
CGFloat finalX = self.view.frame.size.width 
    - self.platformProgressView.frame.size.width * finalScale 
    - finalPadding;
CGFloat finalY = finalPadding;
CGFloat deltaX = finalX - self.platformProgressView.frame.origin.x;
CGFloat deltaY = finalY - self.platformProgressView.frame.origin.y;
[UIView
    animateWithDuration:1.0
    delay:1.0
    options:UIViewAnimationOptionCurveEaseOut
    animations:^(void){
        self.platformProgressView.transform = CGAffineTransformConcat(
            CGAffineTransformMakeTranslation(deltaX, deltaY),
            CGAffineTransformMakeScale(finalScale, finalScale)
        );            
    }
    completion:^(BOOL finished) {
    }
];

最终效果:

 _____________________________
|                            |
|                            |
|                __          |
|               |__|         |
|                            |
|                            |
|                            |
|                            |
|____________________________|

更改乘法的顺序会导致视图偏离屏幕的右边缘。

self.platformProgressView.transform = CGAffineTransformConcat(
     CGAffineTransformMakeScale(finalScale, finalScale),
    CGAffineTransformMakeTranslation(deltaX, deltaY)
);

最终效果(预计):

 _____________________________
|                            |
|                            |    __
|                            |   |__|
|                            |
|                            |
|                            |
|                            |
|                            |
|____________________________|

单独应用它们会导致突然跳跃,最终位置甚至更糟。

self.platformProgressView.transform = CGAffineTransformMakeTranslation(deltaX, deltaY);
self.platformProgressView.transform = CGAffineTransformMakeScale(finalScale, finalScale);

最终效果:

 _____________________________
|                            |
|                            | 
|                            |  
|                            |
|       __                   |
|      |__|                  |
|                            |
|                            |
|____________________________|
21

了解转换

最主要的是,变换的原点是视图矩形的中心点。

首先我们翻译视图。v1 是其原始位置的视图,v2 是其翻译位置的视图。p 是您想要的填充(代码中的finalPadding)。c 标记视图的中心点。

+--------------------------------+
|                        ^       |
|                        | p     |
|                        v       |
|              +- v2 --------+   |
|              |             |   |
|              |      c      |<->|
|              |             | p |
|              +-------------+   |
|                                |
|                                |
|    +- v1 --------+             |
|    |             |             |
|    |      c      |             |
|    |             |             |
|    +-------------+             |
|                                |
+--------------------------------+

接下来我们缩放视图。v3 是处于其缩放位置的视图。注意 v3 的中心点如何保持不变,而它周围的视图尺寸缩小。尽管尺寸是正确的,但视图的定位和产生的填充 p '是错误的。

+--------------------------------+
|                       ^        |
|                       | p'     |
|                       |        |
|                       v        |
|                 +- v3 --+      |
|                 |   c   |<---->|
|                 +-------+  p'  |
|                                |
|                                |
|    +- v1 --------+             |
|    |             |             |
|    |      c      |             |
|    |             |             |
|    +-------------+             |
|                                |
+--------------------------------+

增量计算的修复

现在我们知道了缩放是如何工作的,我们需要修复计算翻译增量的代码。

CGRect windowFrame = self.window.frame;
CGRect viewFrame = self.platformProgressView.frame;
CGPoint finalCenter = CGPointZero;
finalCenter.x = (windowFrame.size.width
                 - (viewFrame.size.width * finalScale) / 2.0f
                 - finalPadding);
finalCenter.y = (finalPadding
                 + (viewFrame.size.height * finalScale) / 2.0f);
CGPoint viewCenter = self.platformProgressView.center;
CGFloat deltaX = finalCenter.x - viewCenter.x;
CGFloat deltaY = finalCenter.y - viewCenter.y;

转换的顺序

最后,正如您自己所指出的,转换与CGAffineTransformConcat连接的顺序很重要。在您的第一次尝试中,您有顺序 1)transform + 2)scale。结果是缩放变换-在序列的后面-影响为翻译变换指定的增量。

这里有 2 个解决方案:要么你自己的第二次尝试,你反转序列,使它变成 1)scale + 2)transform。或者你使用我在我的答案的第一个修订版中建议的 helper 函数。所以这

self.platformProgressView.transform = CGAffineTransformConcat(
    CGAffineTransformMakeScale(finalScale, finalScale),
    CGAffineTransformMakeTranslation(deltaX, deltaY)
);

等于

CGAffineTransform CGAffineTransformMakeScaleTranslate(CGFloat sx, CGFloat sy, CGFloat dx, CGFloat dy)
{
  return CGAffineTransformMake(sx, 0.0f, 0.0f, sy, dx, dy);
}
self.platformProgressView.transform = CGAffineTransformMakeScaleTranslate(finalScale, finalScale, deltaX, deltaY);

不同的解决方案:设置锚点

如果你不满意中心点是视图变换的原点,你可以通过设置视图的 CALayer 的anchorPoint属性来改变这一点。默认的锚点是 0.5 / 0.5,代表视图矩形的中心。显然,锚点不是坐标,而是一种乘法因子。

如果我们假设锚点在视图的左上角,那么您对平移增量的原始计算是正确的。所以如果你这样做

self.platformProgressView.layer.anchorPoint = CGPointMake(0.0f, 0.0f)

你可以保留你原来的计算。

参考

那里可能有更多的信息材料,但是 WWDC 2011 视频Understanding UIKit Rendering是我最近观看的,这极大地帮助我提高了对边界,中心,变换和框架之间关系的理解。

此外,如果您要更改 CALayeranchorPoint属性,您可能应该首先阅读CALayer cl reference中的属性文档。

0

变换适用于所有先前的变换。因此,必须考虑到这一点并仔细考虑顺序。

这些值需要配置为-如果一个发生,然后下一个,即使它们连接到一个变换。

0

这是一个很好的答案,这里是如何在 Swift 4 中做到这一点

 let containerFrame: CGRect  = self.view.frame
    let viewFrame: CGRect  = self.containerView.frame
    var finalCenter: CGPoint  = CGPoint.zero
    let finalPadding: CGFloat  = 0
    let finalScale: CGFloat  = 2.0 //whatever scale that you want
    finalCenter.x = (containerFrame.size.width - (viewFrame.size.width * finalScale) / 2.0 - finalPadding)
    finalCenter.y = (finalPadding + (viewFrame.size.height * finalScale) / 2.0);
    let containerCenter: CGPoint  = self.containerView.center
    let deltaX: CGFloat  = finalCenter.x - containerCenter.x
    let deltaY: CGFloat  = finalCenter.y - containerCenter.y
    let scale = CGAffineTransform(scaleX: finalScale, y: finalScale)
    //MARK: changing the deltas for positive to negative values will change the origin x and y of the transformed view
    let translation = CGAffineTransform(translationX: -deltaX, y: deltaY)
    self.containerView.transform = scale.concatenating(translation)
0

旋转和平移:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let yPos = scrollView.contentOffset.y
    if yPos < 0 {
        let scaleX = ((yPos * -1) / 200) + 1
        let translateY = yPos / 2
        var commonTransform = CGAffineTransform.identity
        commonTransform = commonTransform.translatedBy(x: 0, y: translateY)
        commonTransform = commonTransform.scaledBy(x: scaleX, y: scaleX)
        self.customView?.transform = commonTransform
    }else{
        self.customView?.transform = CGAffineTransform.identity
    }
}

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(349)
SQL语句-CHARINDEX无效函数
上一篇
iges文件怎么写
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(46条)