应用于图层的CATransform3DRotate不起作用

时间:2017-04-07 16:07:23

标签: swift calayer catransform3d

请问你为什么CATransform3DRotate在我的情况下对图层不起作用,为图像上的蓝色层。

enter image description here

我有自定义视图,在那里我绘制自然视图,我想动画更改将在白色圆圈层内完成的月相作为其蒙版。我想在这里申请3DRotation是个好主意,但由于某种原因,即使没有动画它也无法工作,请不要建议我做错了什么?

    func drawMoonPhase(inRect rect:CGRect, inContext context: CGContext) {

    let moonShape = UIBezierPath(ovalIn: rect)
    moonShape.lineWidth = 4.0
    UIColor.white.setStroke()
    moonShape.stroke()
    moonShape.close()

    let moonLayer = CAShapeLayer()
    moonLayer.path = moonShape.cgPath
    moonLayer.opacity = 0
    self.layer.addSublayer(moonLayer)

    let circlePath = UIBezierPath(ovalIn: rect)
    UIColor.blue.setFill()
    circlePath.fill()
    circlePath.close()

    let circleShape = CAShapeLayer()
    circleShape.path = circlePath.cgPath
    circleShape.opacity = 0

    var transform = CATransform3DIdentity
    transform.m34 = -1 / 500.0

    transform = CATransform3DRotate(transform, (CGFloat(Double.pi * 0.3)), 0, 1, 0)
    circleShape.transform = transform

    moonLayer.mask = circleShape

}

提前致谢

编辑: 也许我想要清楚,我想要的效果如下: enter image description here

1 个答案:

答案 0 :(得分:2)

变换发生在图层的锚点附近,默认情况下位于中心。因此,它发生的是形状围绕自身旋转而导致没有可见的结果。 :)

在这个图层布局中你应该做的是使用cos和sin数学函数来确定月亮的x和y位置。

如果您需要更多见解,请告诉我,我们将很乐意为您提供帮助。

另外,请注意,您不需要2个shapeLayers才能拥有白色笔划的蓝色月亮。 CAShapeLayer具有填充和描边属性,因此您可以简化代码。

根据新信息,这是我的新答案:

我无法通过使用变换获得良好的效果,所以我决定手动编写掩码。这是结果:

/**
 Draw a mask based on the moon phase progress.

 - parameter rect: The rect where the mon will be drawn
 - parameter progress: The progress of the moon phase. This value must be between 0 and 1
 */
func moonMask(in rect: CGRect, forProgress progress: CGFloat)->CALayer {
    let path = CGMutablePath()
    let center = CGPoint(x: rect.midX, y: rect.midY)
    path.move(to: CGPoint(x: rect.midX, y: 0))

    let relativeProgress = (max(min(progress, 1), 0) - 0.5) * 2
    let radius = rect.width/2

    let tgX = rect.midX+(relativeProgress * (radius*4/3))
    path.addCurve(to: CGPoint(x: rect.midX, y: rect.maxY), control1: CGPoint(x: tgX, y: 0), control2: CGPoint(x: tgX, y: rect.maxY))
    path.addArc(center: center, radius: rect.width/2, startAngle: .pi/2, endAngle: .pi*3/2, clockwise: false)
    //path.closeSubpath()

    let mask = CAShapeLayer()
    mask.path = path
    mask.fillColor = UIColor.black.cgColor

    return mask
}

上面的函数绘制了一个可用作moonLayer蒙版的shapetain。此图层将与您将在函数中传递的进度参数相关联,其中1是满月,0是新月。

您可以将所有内容放在一起以获得所需的效果,并且您可以提取路径创建代码,以便在需要时制作精美的动画。

这应该回答我希望的问题。 为了快速测试,我写了这个游乐场:

import UIKit

let rect = CGRect(origin: .zero, size: CGSize(width: 200, height: 200))

let view = UIView(frame: rect)
view.backgroundColor = .black
let layer = view.layer

/**
 Draw a mask based on the moon phase progress.

 - parameter rect: The rect where the mon will be drawn
 - parameter progress: The progress of the moon phase. This value must be between 0 and 1
 */
func moonMask(in rect: CGRect, forProgress progress: CGFloat)->CALayer {
    let path = CGMutablePath()
    let center = CGPoint(x: rect.midX, y: rect.midY)
    path.move(to: CGPoint(x: rect.midX, y: 0))

    let relativeProgress = (max(min(progress, 1), 0) - 0.5) * 2
    let radius = rect.width/2

    let tgX = rect.midX+(relativeProgress * (radius*4/3))
    path.addCurve(to: CGPoint(x: rect.midX, y: rect.maxY), control1: CGPoint(x: tgX, y: 0), control2: CGPoint(x: tgX, y: rect.maxY))
    path.addArc(center: center, radius: rect.width/2, startAngle: .pi/2, endAngle: .pi*3/2, clockwise: false)
    //path.closeSubpath()

    let mask = CAShapeLayer()
    mask.path = path
    mask.fillColor = UIColor.white.cgColor

    return mask
}

let moonLayer = CAShapeLayer()
moonLayer.path = UIBezierPath(ovalIn: rect).cgPath
moonLayer.fillColor = UIColor.clear.cgColor
moonLayer.strokeColor = UIColor.white.cgColor
moonLayer.lineWidth = 2
moonLayer.shadowColor = UIColor.white.cgColor
moonLayer.shadowOpacity = 1
moonLayer.shadowRadius = 10
moonLayer.shadowPath = moonLayer.path
moonLayer.shadowOffset = .zero

layer.addSublayer(moonLayer)

let moonPhase = moonMask(in: rect, forProgress: 0.3)
moonPhase.shadowColor = UIColor.white.cgColor
moonPhase.shadowOpacity = 1
moonPhase.shadowRadius = 10
moonPhase.shadowPath = moonLayer.path
moonPhase.shadowOffset = .zero

layer.addSublayer(moonPhase)

view

enter image description here