快速将CAShapelayer转换为特定大小 [英] Transforming a CAShapelayer to a specific size in swift

查看:89
本文介绍了快速将CAShapelayer转换为特定大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使带有贝塞尔曲线路径的CAShapeLayer扩展为具有视图(当然是动画的)。我知道我可以使用CATransform3DMakeScale(,,)来更改路径的大小,但这不能使我使路径的大小正确(以磅为单位)。



有人知道怎么做吗?

解决方案

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



简单解决方案



用不同的措辞来表达您的问题:您拥有一种尺寸的东西(路径/形状层) ),然后将其缩放为另一种尺寸。



要知道要沿X和Y分别缩放多少,请对尺寸进行划分想要适合当前尺寸。您可以使用

  let boundingBox = CGPathGetBoundingBox(path)

我假设您已经具有要缩放的大小(此处我称我为



使用这两个,您可以通过将要缩放的尺寸除以要缩放的尺寸来计算两个缩放因子from

  let xScaleFactor = containsSize.width / boundingBox.width 
让yScaleFactor = containsSize.height / boundingBox.height

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

  let scaleTransform = CATransform3DMakeMakeScale(xScaleFactor,yScaleFactor,1.0)

缩放此形状图层





使用这两个比例因子,将进行缩放形状层以填充容器大小。如果容器大小与路径具有相同的宽高比,则所有内容将按预期显示。如果不是,则缩放的图层将显示为拉伸状态。





拟合而不是填充



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



我们通过找出哪个比例因子是最受限制的比例因子,然后将其同时应用于X和Y

  let boundingBoxAspectRatio = boundingBox.width / boundingBox.height 
让viewAspectRatio = containsSize.width / containsSize.height

let scaleFactor:CGFloat
if(boundingBoxAspectRatio&view; viewAspectRatio){
//宽度是限制因素
scaleFactor = containsSize.width / boundingBox.width
}否则{
//高度是限制因素
scaleFactor = containsSize.height / boundingB ox.height
}

let scaleTransform = CATransform3DMakeMakeScale(scaleFactor,scaleFactor,1.0)

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





缩放图层或缩放路径?



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



如果只希望在缩放形状图层的路径时显示它,则应该缩放路径而不是图层。为此,您可以创建一个新路径进行转换,并在形状图层中使用 that 路径。请注意,比例因子仍使用未缩放路径的边界框进行计算。

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

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




I'm trying to make a CAShapeLayer with a bezier path in it expand with a view (which is animated, of course). I am aware that I could change the size of the path with CATransform3DMakeScale(, , ) But this won't allow me to make the path an exact size (in points).

Does anybody know how to do this?

解决方案

You would do this using good old fashioned math.

Simple solution

To phrase your question differently: you have something of one size (the path/shape layer), and you want to scale it so that it becomes another size.

To know how much you want to scale along X and Y (separately) you divide the size you want to fit to by the current size. You can get the bounding box of the path using

let boundingBox = CGPathGetBoundingBox(path)

I'm assuming that you already have some size that you want to scale it to (here I'm calling mine containingSize).

Using those two, you can calculate the two scale factors by dividing the dimension you are scaling to with the dimension you are scaling from

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

Using those, you can create the required scale transform

let scaleTransform = CATransform3DMakeMakeScale(xScaleFactor, yScaleFactor, 1.0)

Scaling this shape layer

using those two scale factors, will scale the shape layer to fill the container size. If the container size has the same aspect ratio as the path, everything will look as expected. If not, the scaled layer will appear stretched.

Fitting instead of filling

This problem (unless its what you want) can be solved by calculating a uniform scale factor, that is the smaller of the two, so that the scaled path fits the container instead of fills it.

We do this by finding out which scale factor is the most constrained one, and then apply that to both X and 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)

This will scale the path without changing its aspect ratio

Scaling the layer or scaling the path?

You might also have noticed that as the shape layer was scaled, the line width scaled as well, like if it was an image. There is a difference between scaling the layer, and scaling the path.

If you only want it to appear as the path of the shape layer is scaled, then you should scale the path instead of the layer. You can do this by creating a new path that is transformed, and using that path with your shape layer. Note that the scale factor is still calculated using the bounding box of the unscaled path.

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

This will scale up the path, without affecting the line width, etc of the shape layer.

这篇关于快速将CAShapelayer转换为特定大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆