【问题标题】:Transforming a CAShapelayer to a specific size in swift快速将 CAShapelayer 转换为特定大小
【发布时间】:2015-05-25 09:01:02
【问题描述】:

我正在尝试制作一个带有贝塞尔路径的 CAShapeLayer,其中包含一个视图(当然,它是动画的)。我知道我可以使用 CATransform3DMakeScale(, , ) 更改路径的大小,但这不允许我将路径设为精确大小(以磅为单位)。

有人知道怎么做吗?

【问题讨论】:

    标签: ios swift animation cashapelayer


    【解决方案1】:

    您可以使用良好的老式数学来做到这一点。

    简单的解决方案

    换一种说法:你有一个大小的东西(路径/形状层),你想缩放它,使它变成另一个大小。

    要知道您想沿 X 和 Y (分别)缩放多少,您将要适应的尺寸除以当前尺寸。您可以使用

    获取路径的边界框
    let boundingBox = CGPathGetBoundingBox(path)
    

    我假设您已经有了一些想要将其缩放到的大小(这里我叫我的 containingSize)。

    使用这两个,您可以通过将要缩放到的维度除以要缩放的维度来计算两个比例因子

    let xScaleFactor = containingSize.width  / boundingBox.width
    let yScaleFactor = containingSize.height / boundingBox.height
    

    使用这些,您可以创建所需的比例变换

    let scaleTransform = CATransform3DMakeMakeScale(xScaleFactor, yScaleFactor, 1.0)
    

    缩放这个形状层

    使用这两个比例因子,将缩放形状层以填充容器大小。如果容器大小与路径具有相同的纵横比,则一切都将按预期显示。否则,缩放后的图层将显示为拉伸状态。

    拟合而不是填充

    这个问题(除非它是你想要的)可以通过计算一个统一的比例因子来解决,即两者中较小的一个,这样缩放的路径适合容器而不是填充它。

    我们通过找出最受约束的比例因子来做到这一点,然后将其应用于 X 和 Y

    let boundingBoxAspectRatio = boundingBox.width/boundingBox.height
    let viewAspectRatio = containingSize.width/containingSize.height
    
    let scaleFactor: CGFloat
    if (boundingBoxAspectRatio > viewAspectRatio) {
        // Width is limiting factor
        scaleFactor = containingSize.width/boundingBox.width
    } else {
        // Height is limiting factor
        scaleFactor = containingSize.height/boundingBox.height
    }
    
    let scaleTransform = CATransform3DMakeMakeScale(scaleFactor, scaleFactor, 1.0)
    

    这将在不改变纵横比的情况下缩放路径

    缩放图层还是缩放路径?

    您可能还注意到,随着形状图层的缩放,线宽也随之缩放,就像是图像一样。缩放图层和缩放路径是有区别的。

    如果您只希望它显示为形状图层的路径被缩放,那么您应该缩放路径而不是图层。您可以通过创建一个已转换的新路径并将 that 路径与您的形状层一起使用来实现此目的。请注意,缩放因子仍然是使用未缩放路径的边界框计算的。

    var affineTransform = CGAffineTransformMakeScale(scaleFactor, scaleFactor)
    let transformedPath = CGPathCreateCopyByTransformingPath(path, &affineTransform)
    yourShapeLayer.path = transformedPath
    

    这将放大路径,而不影响形状图层的线宽等。

    【讨论】:

    • 当边界框的宽度或高度为0,即路径是直线时,你会怎么做?
    • @luna_ 在这种情况下,您可以根据描边路径计算边界框(使用CGPathCreateCopyByStrokingPath)。当路径被描边时,它会有一个宽度(假设线宽大于零)。
    • 这是一个出色而彻底的答案。谢谢大卫。可能有趣的一点是这两种方法的采样行为。我认为在这两种情况下,您都会缩放图层的 content,因此在这两种情况下,最终渲染都是在设备分辨率下进行的,并且分辨率与使用的缩放比例无关。我尝试了第一种方法,修改了CAShapeLayer 转换属性,它确实以全分辨率呈现。另一个问题是,如果你放大到 10 倍,是否会创建一个巨大的背景纹理——我希望不会!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    相关资源
    最近更新 更多