ios - 沿弧定位 CATextLayers

标签 ios swift cgaffinetransform catextlayer

我正在尝试构建一个自定义控件,它可能看起来像这个 Inkscape 模型:

enter image description here

我正在使用 drawRect() 做一些事情,但我需要为一些元素设置动画,所以我决定切换到 CALayer 的组合。我一直在使用 CGContextRef 函数绘制文本,但是为每个字符切换到 CATextLayer 后,我似乎无法正确转换它们。

我的一般方法是为每个字符创建一个 CATextLayer。我认为我可以使用每一层的preferredFrameSize() 来获取角色的最终大小。然后我想我会在我的控件的 layoutSubviews() 方法中调整它们的位置和旋转。

“我试过什么?”我感觉自己就像一直坐在坐立旋转上,蒙着眼睛,扔飞镖。随便你说,我已经试过了。

我可以用类似的东西来确定每个角色的旋转角度:

let baseline = (self.ringBox.width * 3 / 8) // radius out to the baseline arc
let circumference = baseline * Tau
var advance = wordWidth.half.negated // wordWidth was summed from the width of each character earlier
let angle = 0.75.rotations
for each in self.autoCharacters {
    let charSize = each.bounds.size
    advance += charSize.width.half
    let charRotation = (advance / circumference - 0.75).rotations + angle
    ...
}

我注意到 layoutSubviews() 似乎被调用了两次。为什么?我注意到第二次时,preferredFrameSize() 似乎更细了。为什么?是不是因为我正在设置 affineTransform 并且它具有累积效应。我试图最初将层的位置设置为父框的中心,以及边界为 preferredFrameSize,希望将其居中于中心。然后应用转换。尽管进行了多次尝试,我还是得到了奇怪的位置和奇怪的剪裁。

所以我只是在寻找一个简单/直接的方法,它将 CATextLayer 放置在距 View 中心给定的半径/角度处。

最佳答案

最后,我编写了一个带有 slider 的单独应用程序:

  • 框架原点
  • 帧大小
  • 边界原点
  • 边界大小
  • 职位
  • anchor
  • 预旋转变换平移
  • 变换旋转
  • 后旋转变换翻译

以及一些显示层的 preferredFrameSize() 的调试信息。有了它,能够操纵事物并看到效果,我实际上能够非常简单地把它记下来。

在为给定单词中的每个字符创建单个 CATextLayer 之后(输入为 [CATextLayer]),我使用以下方法定位单词的字符:

// pass 1 to:
// - baseline each characters rotation
// - size it and center it
// - accumulate the length of the whole word
var wordWidth:CGFloat = 0.0
for letter in word {
    // baseline the transform first, because preferredFrameSize() is affected by any latent rotation in the current transform
    letter.setAffineTransform(CGAffineTransformIdentity)
    // the preferredFrameSize will now be the un rotated size of the single character
    let size = letter.preferredFrameSize()
    // move the letter to the center of the view
    letter.frame = CGRect(origin: center - size.half, size: size)
    // accumulate the length of the word as the length of characters
    wordWidth += size.width
}
let Tau = CGFloat(M_PI * 2)
// the length of the circle we want to be relative to
let circumference = radius * Tau
// back up the "advance" to half of the word width
var advance = wordWidth.half.negated
for letter in word {
    // retrieve the character dimensions
    let charSize = letter.bounds.size
    // advance half of the character, so we're at its center
    advance += charSize.width.half
    // determine the angle to rotate off of the nominal (which is 270 degrees)
    let charRotation = (advance / circumference * Tau - (Tau * 3 / 4)) + angle
    // start with an identity transform now
    var transform = CGAffineTransformIdentity
    // rotate it. this will rotate about the center of the character
    transform = transform.rotated(charRotation)
    // translate outwards to the ring
    transform = transform.translated(CGPoint(x: 0, y: radius.negated))
    // apply the transform
    letter.setAffineTransform(transform)
    // move the advance the other half of this character
    advance += charSize.width.half
}

关于ios - 沿弧定位 CATextLayers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32959089/

相关文章:

ios - Clang 在 objective-c 中因退出代码 1 错误而失败

ios - Swift iOS 中的叉积

swift - 从 ViewController 访问 NSDocument

ios - 绘制时对 UIImage 应用变换

autolayout - 在 iOS8 下使用 CGAffineTransform 旋转时 UIView 不会调整大小

ios - 如何设置带有 AND 条件的 NSpredicate 来获取数据

iphone - 当我们滚动自定义表格时,iPhone 中的单元格内容会发生变化

ios - 如果集合中只有 1 个元素,UICollectionView 不会进入 cellForItemAt 方法

ios - 阿联酋 : Voice/Video Calling using Data/WiFi in App - using Swift 4. 0

ios - 旋转 iOS 的 UIImageView 问题