Почему существует смещение при вращении моего CAReplicatorLayer

Я сожалею, чтобы дать статический pictrue, а не gif изображение, поэтому не могу показать вопрос.

Введите описание изображения здесь

Но я даю код демо ниже, так что вы можете проверить в вашем xcode.

 import UIKit

class ViewController: UIViewController {

    var circelWidth:CGFloat = 0.0
    var circle_r_y:CGFloat = 316
    let apear_circle_duration:CFTimeInterval = 1.5

    let turn_ani_repeat_count:Float = 1 // times
    let turn_ani_duration:Float = 0.4 // one circle, how many time, you can change the proerty to look more detail.

    override func viewDidLoad() {
        super.viewDidLoad()

        initData()

        initUI()
    }

    func initData() {

        // 2.圆圈⭕️
        if (Display.typeIsLike == .iphone6 || Display.typeIsLike == .iphone6plus) {

            self.circelWidth = 260 // must set, then animate the circel
        }else {

            self.circelWidth = 230 // must set, then animate the circel
        }
    }

    func initUI() {

        self.view.backgroundColor = UIColor.brown

        self.animateCircle()
    }

    func animateCircle() {

        let r = CAReplicatorLayer()
        r.bounds = CGRect.init(x: 0.0, y: 0.0, width: circelWidth, height: circelWidth)
        r.cornerRadius = 10.0  // 10
        r.backgroundColor = UIColor.clear.cgColor

        // var circle_r_y:CGFloat = 160.0
        circle_r_y = (UIScreen.main.bounds.size.height - 64) / 2.0 + 64

        r.position = CGPoint.init(x: self.view.bounds.width / 2.0, y: circle_r_y)

        //r.anchorPoint = CGPoint.init(x: 0.5, y: circle_r_y! / r.bounds.height)  // 锚点设置
        r.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
        self.view.layer.addSublayer(r)

        // dot
        let dot = CALayer()
        dot.bounds = CGRect(x:0.0, y :0.0, width:6.0, height:6.0)
        dot.position = CGPoint(x:100.0, y:10.0)
        dot.backgroundColor = UIColor(white:1, alpha:1.0).cgColor
        dot.cornerRadius = 3.0 // half of dot width 一半

        r.addSublayer(dot)

        let nrDots: Int = 32
        r.instanceCount = nrDots
        let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
        r.instanceTransform = CATransform3DMakeRotation(angle, 0.1, 0.1, 1.0)


        let shrink = CABasicAnimation(keyPath: "transform.scale")
        shrink.fromValue = 1.0
        shrink.toValue = 1.0 // 0.5
        shrink.duration = apear_circle_duration
        shrink.repeatCount = Float.infinity

        dot.add(shrink, forKey: nil)

        r.instanceDelay = apear_circle_duration/Double(nrDots)

        dot.transform = CATransform3DMakeScale(0.1, 0.1, 0.1)

        delay(delay: apear_circle_duration) {

            let turn_key_path = "transform.rotation"
            let turn_ani = CABasicAnimation.init(keyPath: turn_key_path)
            turn_ani.isRemovedOnCompletion = false
            turn_ani.fillMode = kCAFillModeForwards
            turn_ani.toValue = M_PI*2
            turn_ani.duration = CFTimeInterval(self.turn_ani_duration)
            turn_ani.repeatCount = self.turn_ani_repeat_count
            r.add(turn_ani, forKey: turn_key_path)

            dot.transform = CATransform3DMakeScale(1, 1, 1)  // 设置回来,不然再出现会放小

        }
    }

    func delay(delay:Double, closure:@escaping ()->()){

        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }

    }

TheDisplay.swift, it is check the device type.

import UIKit

public enum DisplayType {
case unknown
case iphone4
case iphone5
case iphone6
case iphone6plus
static let iphone7 = iphone6
static let iphone7plus = iphone6plus
}

    public final class Display {
    class var width:CGFloat { return UIScreen.main.bounds.size.width     }
    class var height:CGFloat { return UIScreen.main.bounds.size.height }
    class var maxLength:CGFloat { return max(width, height) }
    class var minLength:CGFloat { return min(width, height) }
    class var zoomed:Bool { return UIScreen.main.nativeScale >= UIScreen.main.scale }
    class var retina:Bool { return UIScreen.main.scale >= 2.0 }
    class var phone:Bool { return UIDevice.current.userInterfaceIdiom == .phone }
    class var pad:Bool { return UIDevice.current.userInterfaceIdiom == .pad }
    class var carplay:Bool { if #available(iOS 9.0, *) {
        return UIDevice.current.userInterfaceIdiom == .carPlay
    } else {
        // Fallback on earlier versions
        return false//UIDevice.current.userInterfaceIdiom == carplay
    }
    }
    class var tv:Bool { if #available(iOS 9.0, *) {
        return UIDevice.current.userInterfaceIdiom == .tv
    } else {
        // Fallback on earlier versions

        return false
        }
    }
class var typeIsLike:DisplayType {
    if phone && maxLength < 568 {
        return .iphone4
    }
    else if phone && maxLength == 568 {
        return .iphone5
    }
    else if phone && maxLength == 667 {
        return .iphone6
    }
    else if phone && maxLength == 736 {
        return .iphone6plus
    }
    return .unknown
}
}

Вопрос

Если вы тестируете это в своем проекте вы можете найти проблему, при анимации, есть небольшое смещение, это странная проблема, потому что , я уверенCAReplicatorLayer, что ‘S ahchorPointесть(0.5, 0.5), но почему есть смещение?

Если вы хотите посмотреть более подробно, вы можете изменить значение turn_ani_duration:Float‘ s, Вы можете увидеть смещение.

1 ответ

  1. Возможно, слишком поздно, но это вызвано вектором, который вы предоставляете своему преобразованию поворота :
    заменять
    r.instanceTransform = CATransform3DMakeRotation(angle, 0.1, 0.1, 1.0)
    от
    r.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1.0)
    и это нормально.