【iOS】- Swift 旋转+轨迹动画制作加载页面

具体动画
1242701-bc21f72752a5d367.gif

如上图,动画可以拆分为三部分

  • 1 . 中间扇叶的旋转动画!
  • 2 . 两边的画线轨迹!
  • 3 . 动态变化的进度显示!

中间扇叶动画

我这边使用的4张图片,已附上:


>
02.png
03.png
juhua.png

很明显了是吧,只需要把图片加上去,然后旋转起来就可以了。
那么怎么让它变成旋转的呢?其实很简单,Apple 就已经提供给我们很好的API 以供使用!

图片旋转

声明部分

    /// 菊花视图
    lazy var hudImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "bgImage")
        return imageView
    }()
    
    ///叶子视图1
    lazy var imageView1: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "image01")
        return imageView
    }()
    
    ///叶子视图2
    lazy var imageView2: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "image02")
        return imageView
    }()
    
    ///叶子视图3
    lazy var imageView3: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "image03")
        return imageView
    }()
    /// 初始旋转角度
    var angleHud = CGFloat(1);
    var angle1 = CGFloat(1);
    var angle2 = CGFloat(1);
    var angle3 = CGFloat(1);

    /// 是否停止动画
    var isStop = false

旋转图片实现方法

    /// 开始图片动画
    private func startImageView(){
        
        //选择动画:
        
        let endAnglehud = CGAffineTransform(rotationAngle: angleHud * .pi / 180)
        let endAngle1 = CGAffineTransform(rotationAngle: angle1 * .pi / 180)
        let endAngle2 = CGAffineTransform(rotationAngle: angle2 * .pi / 180)
        let endAngle3 = CGAffineTransform(rotationAngle: angle3 * .pi / 180)
        
        
        UIView.animate(withDuration: 0.01) {
            
            self.hudImageView.transform = endAnglehud
            self.imageView1.transform = endAngle1
            self.imageView2.transform = endAngle2
            self.imageView3.transform = endAngle3
            
        } completion: { finished in
            self.angleHud -= 4;
            self.angle1 += 4;
            self.angle2 -= 4;
            self.angle3 += 4;
//
            if !self.isStop {
                self.startImageView()
            }
        }
    }

图片旋转实现并不难,直接使用就可以了,如上
然后需要旋转多少,速度都可以更改以上的参数进行自己喜好调整

UI加载部分

    /// 菊花内容 - 宽高
    let hudSize = CGSize(width: 120, height: 120)

    /// 进度Lable
    lazy var progressLable: UILabel = {
        let lable = UILabel()
        lable.textColor = mainColor
        lable.font = UIFont.systemFont(ofSize: 12)
        lable.textAlignment = .center
        lable.text = "0%"
        return lable
    }()
    /// 主颜色
    let mainColor = UIColor(red: 239/255, green: 223/255, blue: 183/255, alpha: 1)
   
 // MARK: - UI实现
    func loadUI() -> Void {
        
        self.addSubview(bgImageView)
        
        bgImageView.addSubview(imageView1)
        
        bgImageView.addSubview(imageView2)
        
        bgImageView.addSubview(imageView3)
        
        bgImageView.addSubview(hudImageView)
        
        bgImageView.addSubview(progressLable)
        
    }
    
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        bgImageView.frame = self.bounds
        
        imageView1.center = bgImageView.center
        imageView1.frame.size = hudSize
        
        imageView2.center = bgImageView.center
        imageView2.frame.size = hudSize
        
        imageView3.center = bgImageView.center
        imageView3.frame.size = hudSize
        
        hudImageView.center = bgImageView.center
        hudImageView.frame.size = hudSize
        
        progressLable.center = bgImageView.center
        progressLable.frame.size = CGSize(width: 50, height: 50)
        progressLable.layer.cornerRadius = progressLable.frame.height/2
        progressLable.layer.masksToBounds = true
        progressLable.layer.borderColor = progressLable.textColor.cgColor
        progressLable.layer.borderWidth = 0.8
        
    }
    

以上实现就不需要过多叙述了,进度的使用的是一个Lable.

那么说下,最后一个,前言说到的画线轨迹动画!

很明显,动画轨迹来看,一个直线和一个半圆,
既然如此,那么就可以按照这个想法来进行实现!我们都知道,iOS中有个很强大的类,UIBezierPath 轨迹画线!
可供参考的 :
UIBezierPath苹果官方API文献
简书李国安的文章

下面就是代码实现部分,先贴代码:
    /// 重写系统 绘制方法
    override func draw(_ rect: CGRect) {
        
        ///上半部轨迹
        let path = UIBezierPath()
        //起点
        path.move(to: CGPoint(x: self.frame.width, y: self.center.y))
        //直线终点
        path.addLine(to: CGPoint(x: self.center.x+hudSize.width/2, y: self.center.y))
        path.addArc(withCenter: self.center, radius: 60, startAngle: .pi*2, endAngle: .pi*1, clockwise: false)
        
        let caShapelayer = CAShapeLayer()
        caShapelayer.path = path.cgPath
        //线条宽度
        caShapelayer.lineWidth = 1.5
        //线条颜色
        caShapelayer.strokeColor = mainColor.cgColor
        //填充颜色
        caShapelayer.fillColor = UIColor.clear.cgColor
        caShapelayer.frame = self.bounds
        self.layer.addSublayer(caShapelayer)
        

        ///下半部轨迹
        let path2 = UIBezierPath()
        //起点
        path2.move(to: CGPoint(x: 0, y: self.center.y))
        //直线终点
        path2.addLine(to: CGPoint(x: self.center.x-hudSize.width/2, y: self.center.y))
        path2.addArc(withCenter: self.center, radius: 60, startAngle: .pi*1, endAngle: .pi*2, clockwise: false)
        
        let caShapelayer2 = CAShapeLayer()
        caShapelayer2.path = path2.cgPath
        //线条宽度
        caShapelayer2.lineWidth = 1.5
        //线条颜色
        caShapelayer2.strokeColor = mainColor.cgColor
        //填充颜色
        caShapelayer2.fillColor = UIColor.clear.cgColor
        caShapelayer2.frame = self.bounds
        self.layer.addSublayer(caShapelayer2)
        
        
        DispatchQueue.main.async {
            self.drawLineAnimation(layer: caShapelayer)
            self.drawLineAnimation(layer: caShapelayer2)
        }
        
    }

    /// 轨迹动画添加到Self- 轨迹动画
    func drawLineAnimation(layer:CALayer) -> Void {
        
        let bas = CABasicAnimation.init(keyPath: "strokeEnd")
        bas.duration = 3
        bas.delegate = self
        bas.fromValue = 0
        bas.toValue = 1
        layer.add(bas, forKey: "key")
    }
    

总体来说,上下部分轨迹,实际上是一样的,所以就分析其中一个就可以了,首先,确定path 轨迹起点,拐点,和终点!

        ///上半部轨迹
        let path = UIBezierPath()
        //起点
        path.move(to: CGPoint(x: self.frame.width, y: self.center.y))
        //直线终点
        path.addLine(to: CGPoint(x: self.center.x+hudSize.width/2, y: self.center.y))
        //圆路径
        path.addArc(withCenter: self.center, radius: 60, startAngle: .pi*2, endAngle: .pi*1, clockwise: false)

直线路径无需多说,注释已经很清晰了,主要说下,半圆轨迹:

系统方法

        open func addArc(withCenter center: CGPoint,
                         radius: CGFloat,
                         startAngle: CGFloat,
                         endAngle: CGFloat,
                         clockwise: Bool)
  • center : 顾名思义就是圆的中心点,学过数学的都知道!
  • radius: 圆的半径!
  • startAngle: 圆轨迹起始的弧度!
  • endAngle : 圆轨迹结束的弧度!
  • clockwise : 是否顺时针!

封装API,提供外部使用

    /// 单例
    static let shareView = AnimationLoadView()
    
    /// 快捷初始化
    public static func show() -> Void{

        let window = UIApplication.shared.delegate?.window!
        shareView.backgroundColor = .black
        shareView.frame = UIScreen.main.bounds
        window!.addSubview(shareView)
        shareView.start()
    }
    
    
    /// 开始动画
    public func start() -> Void {
        
        startImageView()
        
    }
    
    
    /// 结束动画
    public func stop() -> Void {
        
        isStop = true
        progressLable.text = "0%"
        self.angleHud = 1;
        self.angle1 = 1;
        self.angle2 = 1;
        self.angle3 = 1;
        self.removeFromSuperview()
    }

至此所有的动画效果都已经完成,在有需要的地方进行调用,就可以了!

ps: 不当之处还请海涵,分享以及记录自己的代码,请不喜勿喷!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容