Как создать эффект CAAnimation, как Луна вращается вокруг Земли и вращается одновременно в IOS?
Я знаю, что просто создать эффект, заставляющий Луну кружить вокруг Земли в IOS. Предположим, что луна является объектом CALayer, просто измените точку привязки этого объекта на Землю, тогда она оживит кружение вокруг Земли. Но как создать луну, которая вращается сама собой? поскольку у луны может быть только одна точка привязки, кажется, я не могу заставить этот объект CALayer вращаться сам по себе. Что, вы парни, думаете? Благодарю.
3 ответа
Используйте два слоя.
Одна из них - невидимая "рука", простирающаяся от Земли до Луны. Это делает преобразование поворота вокруг своей точки привязки, которая является центром земли. Это приводит к тому, что луна в конце "руки" вращается вокруг земли.
Другой - это луна. Это подслой "руки", сидящий на конце руки. Если вы хотите, чтобы он вращался независимо, вращайте его вокруг точки привязки, которая является его собственным центром.
(Однако следует помнить, что настоящая луна этого не делает. Для настоящей луны "рука" достаточна, потому что настоящая луна вращается синхронно с собственным вращением вокруг Земли - так что мы видим всегда одно и то же лицо луны.)
Вы можете заставить "луну" вращаться вокруг точки, анимируя ее по безье-траектории, и в то же время анимировать преобразование вращения. Вот простой пример,
@interface ViewController ()
@property (strong,nonatomic) UIButton *moon;
@property (strong,nonatomic) UIBezierPath *circlePath;
@end
@implementation ViewController
-(void)viewDidLoad {
self.moon = [UIButton buttonWithType:UIButtonTypeInfoDark];
[self.moon addTarget:self action:@selector(clickedCircleButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.moon];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
CGRect circleRect = CGRectMake(60,100,200,200);
self.circlePath = [UIBezierPath bezierPathWithOvalInRect:circleRect];
self.moon.center = CGPointMake(circleRect.origin.x + circleRect.size.width, circleRect.origin.y + circleRect.size.height/2.0);
}
- (void)clickedCircleButton:(UIButton *)sender {
CAKeyframeAnimation *orbit = [CAKeyframeAnimation animationWithKeyPath:@"position"];
orbit.path = self.circlePath.CGPath;
orbit.calculationMode = kCAAnimationPaced;
orbit.duration = 4.0;
orbit.repeatCount = CGFLOAT_MAX;
[self.moon.layer addAnimation:orbit forKey:@"circleAnimation"];
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
fullRotation.fromValue = 0;
fullRotation.byValue = @(2.0*M_PI);
fullRotation.duration = 4.0;
fullRotation.repeatCount = CGFLOAT_MAX;
[self.moon.layer addAnimation:fullRotation forKey:@"Rotate"];
}
Эти конкретные значения приведут к тому, что "луна" будет иметь то же лицо к центру, что и луна Земли.
Сам искал такую реализацию. Я последовал ответу user1285133 и использовал эту быструю версию:
class ViewController: UIViewController {
var circlePath: UIBezierPath!
var moon = UIButton(frame: CGRect(x: 10, y: 10, width: 50, height: 50))
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() {
let circleRect = CGRect(x: 60, y: 100, width: 200, height: 200)
self.circlePath = UIBezierPath(ovalIn: circleRect)
self.moon.center = CGPoint(x: circleRect.origin.x + circleRect.size.width, y: circleRect.origin.y + circleRect.size.height/2.0)
self.moon.addTarget(self, action: #selector(didTap), for: .touchUpInside)
moon.backgroundColor = .blue
self.view.addSubview(moon)
}
@objc func didTap() {
let orbit = CAKeyframeAnimation(keyPath: "position")
orbit.path = self.circlePath.cgPath
orbit.calculationMode = .paced
orbit.duration = 4.0
orbit.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
moon.layer.add(orbit, forKey: "circleAnimation")
let fullRotation = CABasicAnimation(keyPath: "transform.rotation.z")
fullRotation.fromValue = 0
fullRotation.byValue = CGFloat.pi*2
fullRotation.duration = 4
fullRotation.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
moon.layer.add(orbit, forKey: "Rotate")
}
}