iOSでは、ドトーンポイントの動画効果を実現します。


本論文の例では、iOSの手ぶれ補正動画の具体的なコードを共有します。参考にしてください。具体的な内容は以下の通りです。
1.概要
最近は震える声が好きなアニメの効果を褒めてくれるのを見ました。好奇心があって、自分もアニメの効果を真似て書いてみました。好きではない友達にスプレーしないでください。
話は多くなくて、まず実行効果を見にきます。

2.アニメーション分析
上の例の効果はちょっと速いです。今はゆっくり見て、アニメーションの構成を分析しています。

今回はよく見ましたね。ははは。
2.1アニメーションプロセスの分析
10秒のいいアニメで分析してみましょう。
いいね
1、クリックする時、白い愛は徐々にある程度まで小さくなり、そして赤い愛になります。3秒)
2、赤い愛が徐々に大きくなり、最終的には緩衝動画があり、元のサイズに戻ります。7秒)
3、赤いハートが大きくなった時、赤いリングがだんだん大きくなって、丸い輪の幅が小さくなって、小さくなって消えます。5秒)
4、赤い愛が大きくなる時、愛をめぐる6つの三角形があります。三角形は小さいから大きくなり、また小さくなります。7秒)
5、注意してください。2、3、4のアニメーションは1アニメーションが終了した後に同時に実行されます。つまり、3秒遅れて実行されます。
コメントをキャンセルする時:
1、クリックした後に赤い愛がだんだん小さくなります。
2、小さくなったら、見えないように設定し、元のサイズに戻ります。
2.2コードの原理分析の実現
1、UIViewをカスタマイズして、二つのUImageViewを追加して、それぞれ赤い愛と白い愛を表示して、赤い愛は白い愛の上にあります。そして赤い愛は見えません。
2、UID Viewにクリックジェスチャーを追加します。
3、クリックした時に「いいね」と判断しますか?それとも「いいね」をキャンセルしますか?
4、UID Viewが2つ持っている動画で、白いImageViewのトランスフォームを小さくして見えなくなり、赤いImageViewのトランスフォームを設定して大きくなり、大きくなったら白いImageViewのトランスフォームを元のサイズに戻します。
5、ベジェ曲線とCAShape Layerを通して円環を描き、円環にアニメーショングループCAAnimation Groupを追加しました。アニメーショングループには基本アニメーションCABaic Animation(円環を小さい時から大きくします)とキーフレームアニメーションCAKeyframe Animation(円環幅を小さくして小さくします。)が追加されています。
6、ベジェ曲線とCAShapeLayer循環によって6つの三角形を描き、CATrans form 3 DCMakeRotationを通じて6つの三角形を回転させて、愛を一周させます。
7、各三角形にキーフレームアニメーションを追加します。
8、もし賛成を取り消すなら、比較的簡単で、次第に赤色の愛を小さくして、そして設定が見えなくなります。白い愛は自然に現れます。
9、アニメーションの実行中に、ユーザーのインタラクションをオフにして、アニメーションが終わるまで、ユーザーのインタラクションを再開します。
いくつかの分析は簡単ですが、コードを見るより直接的なものはありません。
3.すべてのコード
コードには多くのコメントが追加されていて、分かりやすいです。

import UIKit
 
public class LikeView: UIView {
 
 //       
 fileprivate var likeImageView = UIImageView()
 //       
 fileprivate var unLikeImageView = UIImageView()
 // true:   , false:    
 fileprivate var isLike: Bool = false
 //     ,   
 public var duration: CFTimeInterval = 0.5
 
 override init(frame: CGRect) {
 super.init(frame: frame)
 setupUI()
 }
 
 required init?(coder: NSCoder) {
 super.init(coder: coder)
 setupUI()
 }
 
 fileprivate func setupUI() {
 //         
 unLikeImageView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
 unLikeImageView.image = UIImage(named: "icon_like_before")
 addSubview(unLikeImageView)
 
 //         ,      。               。
 likeImageView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
 likeImageView.image = UIImage(named: "icon_like_after")
 likeImageView.alpha = 0
 addSubview(likeImageView)
 
 //       
 let tap = UITapGestureRecognizer(target: self, action: #selector(tapLikeAction))
 self.addGestureRecognizer(tap)
 }
 
 //     
 @objc fileprivate func tapLikeAction() {
 //          ,      。
 self.isUserInteractionEnabled = false
 isLike = !isLike
 
 //   
 if isLike {
 //          
 likeImageView.alpha = 0
 
 //           0.2 。
 self.likeImageView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
 
 /*     ,        ,      ,           。*/
 
 UIView.animate(withDuration: duration * 0.3, delay: 0, options: .curveEaseInOut) { [weak self] in
 //           0.2 ,
 self?.unLikeImageView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
 } completion: { [weak self] (finished) in
 //         ,   0.2   。
 self?.likeImageView.alpha = 1
 let duration = self?.duration ?? 0.5
 //        ,        
 UIView.animate(withDuration: duration * 0.7, delay: 0.1, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.8, options: .curveEaseInOut) {
  //           
  self?.likeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
 } completion: { (finished) in
  //        ,         ,      。
  self?.unLikeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
  self?.isUserInteractionEnabled = true
 }
 }
 
 //*****************        ,            。******************//
 
 //      
 let circleStartPath = UIBezierPath(arcCenter: likeImageView.layer.position, radius: self.bounds.size.width / 6, startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true)
 
 //      
 let radius = sqrt(powf(Float(self.bounds.size.width), 2) + powf(Float(self.bounds.size.height), 2))/2
 let circleEndPath = UIBezierPath(arcCenter: likeImageView.layer.position, radius: CGFloat(radius), startAngle: 0, endAngle: CGFloat(2*Double.pi), clockwise: true)
 
 //       ,      。
 let circleLayer = CAShapeLayer()
 circleLayer.strokeColor = UIColor.red.cgColor
 circleLayer.fillColor = UIColor.clear.cgColor
 self.layer.insertSublayer(circleLayer, below: self.likeImageView.layer)
 
 //            
 var currentTimeInSuper = self.layer.convertTime(CACurrentMediaTime(), from: nil)
 var currentTimeLocal = circleLayer.convertTime(currentTimeInSuper, from: self.layer)
 
 //            
 let circleGroupDuration = duration * 0.5
 
 //      
 let circleGroup = CAAnimationGroup()
 circleGroup.duration = circleGroupDuration
 //          ,               ,         。
 circleGroup.beginTime = currentTimeLocal + duration * 0.3
 
 //           
 let circlePathAnimation = CABasicAnimation(keyPath: "path")
 circlePathAnimation.fromValue = circleStartPath.cgPath
 circlePathAnimation.toValue = circleEndPath.cgPath
 
 //           ,   ,   。
 let circleLineWidthAnimation = CAKeyframeAnimation(keyPath: "lineWidth")
 circleLineWidthAnimation.values = [1.0, 4.0, 0.3]
 circleLineWidthAnimation.keyTimes = [0.0, 0.7, 0.9]
 
 //               。
 circleGroup.animations = [circlePathAnimation, circleLineWidthAnimation]
 
 //           。
 circleLayer.add(circleGroup, forKey: nil)
 //**********************************************************************//
 
 //*****************      6        ,            。******************//
 //          ,       
 for i in 0..<6 {
 //      
 let height = self.bounds.size.height / 2 + 12
 //       
 let width = self.bounds.size.width / 10
 
 //            
 let triangleStartPath = UIBezierPath()
 triangleStartPath.move(to: .zero)
 triangleStartPath.addLine(to: CGPoint(x: -1, y: -1))
 triangleStartPath.addLine(to: CGPoint(x: 1, y: -1))
 triangleStartPath.close()
 
 //               
 let triangleMiddlePath = UIBezierPath()
 triangleMiddlePath.move(to: .zero)
 triangleMiddlePath.addLine(to: CGPoint(x: -width/2, y: -height))
 triangleMiddlePath.addLine(to: CGPoint(x: width/2, y: -height))
 triangleMiddlePath.close()
 
 //            
 let triangleEndPath = UIBezierPath()
 triangleEndPath.move(to: CGPoint(x: 0, y: -height))
 triangleEndPath.addLine(to: CGPoint(x: -width/2, y: -height))
 triangleEndPath.addLine(to: CGPoint(x: width/2, y: -height))
 triangleEndPath.close()
 
 //        
 let shapeLayer = CAShapeLayer()
 //         ,   。
 shapeLayer.position = self.likeImageView.layer.position
 shapeLayer.fillColor = UIColor.red.cgColor
 //        。
 shapeLayer.transform = CATransform3DMakeRotation(CGFloat(Double.pi/3) * CGFloat(i), 0, 0, 1)
 
 self.layer.insertSublayer(shapeLayer, below: circleLayer)
 
 //             
 currentTimeInSuper = self.layer.convertTime(CACurrentMediaTime(), from: nil)
 currentTimeLocal = shapeLayer.convertTime(currentTimeInSuper, from: self.layer)
 
 //         ,       。
 let trianglePathAnimation = CAKeyframeAnimation(keyPath: "path")
 trianglePathAnimation.values = [triangleStartPath.cgPath, triangleMiddlePath.cgPath, triangleEndPath.cgPath]
 trianglePathAnimation.keyTimes = [0.0, 0.3, 0.7]
 trianglePathAnimation.duration = duration * 0.7
 trianglePathAnimation.beginTime = currentTimeLocal + duration * 0.3
 
 shapeLayer.add(trianglePathAnimation, forKey: nil)
 }
 //**********************************************************************//
 }else {
 //     
 // 1.              0.1 ,                。
 UIView.animate(withDuration: duration * 0.3, delay: 0, options: .curveEaseInOut) { [weak self] in
 self?.likeImageView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
 } completion: { [weak self] (finished) in
 self?.likeImageView.alpha = 0
 self?.likeImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
 self?.isUserInteractionEnabled = true
 }
 }
 }
}
LikeViewは、カスタムのポイントビューであり、コードを純粋に作成することができます。また、xibを通じて作成することもできます。アニメーションの実行時間を設定するdurationをサポートします。
呼び出し場所:

class ViewController: UIViewController {
 
 override func viewDidLoad() {
 super.viewDidLoad()
 view.backgroundColor = UIColor.black
 //     0.5    
 let likeView1 = LikeView(frame: CGRect(x: 110, y: 300, width: 50, height: 50))
 likeView1.duration = 0.5
 self.view.addSubview(likeView1)
 
 //     10    
 let likeView2 = LikeView(frame: CGRect(x: 240, y: 300, width: 50, height: 50))
 likeView2.duration = 10
 self.view.addSubview(likeView2)
 }
 
}
実行効果:

4.結語
コードには主にUID Viewの基礎アニメーション、CGAffine Trans form、CATransform 3 D、UICBezerPath、CAShape Layer、CAKeyframe Animation、CABaic Animation、CAAnimation Group、その他にbeging Timeの計算もあります。
以上はただ震えをまねてアニメーションの実現の機能をほめて、コードは多くなくて、しかしも少なくなくて、震え音が具体的にどのように実現するのなことを知らないで、もし何か間違いがあるならば、あるいは最適化することができる地方、また通る友達によけいに教えてもらいます。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。