swift gift animation

Recently, I made a gift animation written with swift. This animation was originally used in the project. Then when the project needs to be changed, I think I can use swift to encapsulate it for reference.
Want to see the effect picture:



Design sketch

thinking

1. First create an animated data model.

struct AnimationModel{
    var userHead:String?
    var giftNum:Int?
    var giftHeadImage:String?
    var giftUserName:String?
    var giftName:String?
    
    init(dict:[String:String]) {
        
        if let userHead = dict["userhead"]{
            self.userHead = userHead
        }
        
        if let giftName = dict["giftname"]{
            self.giftName = giftName
        }
        
        if let giftNum = Int(dict["giftnum"] ?? "0") {
            self.giftNum = giftNum
        }
        
        if let giftHeadImage = dict["giftheadimage"]{
            self.giftHeadImage = giftHeadImage
        }
        
        if let giftUserName = dict["giftusername"]{
            self.giftUserName = giftUserName
        }
        
    }
    
}

2. Customize an animation view that controls the number of gifts it has.

class AnimationLabel: UIView {
    var myTimer:Timer?
    var num:Int?
    var giftCount:Int?
    var model: AnimationModel?{
        didSet{
            self.headView.image = UIImage(named:model?.userHead ?? "head")
            self.giftImageView.image = UIImage(named:model?.giftHeadImage ?? "head")
            self.labelName.text = model?.giftUserName
            self.labelGift.text = "Give\(model?.giftName ?? "anonymous")"
        }
    }
    
    lazy var headView: UIImageView = {
        let frame = CGRect(x: 5, y: 5, width: self.frame.height - 10, height: self.frame.height - 10)
        return self.getImageView(frame: frame, stringImage: "head")
    }()
    
    lazy var labelName: UILabel = {
        let frame = CGRect(x: self.headView.frame.maxX+5, y: self.headView.frame.minY+5, width: self.frame.width - 10, height: 20)
        let label = self.getlabeView(frame: frame, title: "That's my name")
        label.textColor = UIColor.rgb(239, 202, 139, 1.0)
        return label
    }()
    
    lazy var labelGift: UILabel = {
        let frame = CGRect(x: self.labelName.frame.minX, y: self.labelName.frame.maxY+5, width: self.frame.width, height: 20)
        let label = self.getlabeView(frame: frame, title: "Give red lips")
        return label
    }()
    
    lazy var labelCount: UILabel = {
        let frame = CGRect(x: self.labelGift.frame.maxX + 5, y: self.labelGift.frame.minY, width: self.frame.width, height: 20)
        let label = self.getlabeView(frame: frame, title: "x1")
        label.font = UIFont.systemFont(ofSize: 15)
        label.textColor = UIColor.red
        return label
    }()
    
    lazy var giftImageView: UIImageView = {
        let frame = CGRect(x: self.labelName.frame.maxX, y: 0, width: 40, height: 40)
        return self.getImageView(frame: frame, stringImage: "gift")
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.num = 1
        addSubview(headView)
        addSubview(labelName)
        addSubview(labelGift)
        addSubview(labelCount)
        addSubview(giftImageView)
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

3. The zoom-in and zoom-out animation is controlled by a timer, dividing the total number of gifts by a number, which is the number of overlays after each zoom-in and zoom-out animation is completed. Stop animating until the number of overlays equals the total number of gifts.And remove it from the parent view.

extension AnimationLabel{
    
    func getImageView(frame:CGRect, stringImage:String) -> UIImageView {
        let imageView = UIImageView(frame: frame)
        imageView.image = UIImage(named:stringImage)
        return imageView
    }
    
    func getlabeView(frame:CGRect, title:String) -> UILabel {
        let label = UILabel(frame: frame)
        label.text = title
        label.font = UIFont.systemFont(ofSize: 12)
        return label
    }

    //Start animation of the number of gifts
    func startTimer(){
        self.myTimer = Timer(timeInterval: 0.7, target: self, selector: #selector(mystartAnimation), userInfo: nil, repeats: true)
        RunLoop.current.add(self.myTimer!, forMode: .defaultRunLoopMode)
    }
    
    func stopTimer(){
        self.myTimer?.invalidate()
        self.myTimer = nil
    }
    
    
    @objc func mystartAnimation(){
        let add = floorf(Float(self.giftCount!) / 5.0)
        if self.num! >= self.giftCount! {
            self.num = self.giftCount
            self.stopTimer()
            UIView.animate(withDuration: 1.0, animations: {
                self.alpha = 0
            }, completion: { finish in
                self.removeFromSuperview()
            })
        }
        
        UIView.animateKeyframes(withDuration: 0.25, delay: 0, options: .allowUserInteraction, animations: {
            
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0, animations: {
                self.labelCount.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
                self.labelCount.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
            })
            
        }) { (finish) in
            
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 8, options: .curveEaseInOut, animations: {
                self.labelCount.text = "x\(self.num!)"
                self.num! += Int(add)
                self.labelCount.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
            }, completion: { finish in
                
            })
        }
        
    }
}

4. When the custom view is complete, consider animations that pan from left to up.Pan right from the left and pan right through the UIView animation. Then pan up here, considering using scrollview's contentOffset to control it.Each time you add a gift view, pan up a fixed offset, then add the fixed offset to its y value when the next view is added.

class SendGiftAnimationScrollView: UIScrollView {

    var numHeight:CGFloat!
    var viewY:CGFloat!
    var margin:CGFloat!
    override init(frame: CGRect) {
        super.init(frame: frame)
        numHeight = 0
        viewY = 350
        margin = 85
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func addAnimationLabel(dict: [String:String]){
        let animate = AnimationLabel(frame: CGRect(x: -100, y: self.viewY, width: 100, height: 80))
        let model = AnimationModel(dict: dict)
        animate.model = model
        animate.giftCount = model.giftNum
        self.addanimationView(sender: animate)
        
        self.viewY! += margin
    }
    
    private func addanimationView(sender:AnimationLabel) {
        var frame = sender.frame
        frame.origin.x = 0
        self.addSubview(sender)
        UIView.animate(withDuration: 0.5, animations: {
            sender.frame = frame
        }) { (finish) in
            let point = CGPoint(x: 0, y: self.numHeight)
            self.setContentOffset(point, animated: true)
            sender.startTimer()
        }
        
        self.numHeight! += margin
    }
}

5. Last look at the call

var scrollView: SendGiftAnimationScrollView?
    override func viewDidLoad() {
        super.viewDidLoad()
        self.scrollView = SendGiftAnimationScrollView(frame: CGRect(x: 0, y: 0, width: view.frame.width*0.7, height: view.frame.height))
        self.scrollView?.backgroundColor = UIColor(white: 0, alpha: 0.7)
        view.addSubview(self.scrollView!)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let dic = ["userhead":"Head portrait","giftnum":"99","giftheadimage":"Gift 1","giftusername":"Different fireworks","giftname":"An crown"]
        let dic2 = ["userhead":"Avatar 2","giftnum":"9","giftheadimage":"Gift 2","giftusername":"uncomplicated","giftname":"Red lips"]
        self.scrollView?.addAnimationLabel(dict: dic)
        self.scrollView?.addAnimationLabel(dict: dic2)
    }

Keywords: Swift

Added by Stingus on Tue, 21 May 2019 20:20:47 +0300