最近做了一个用swift写的送礼动画,这个动画本来是在项目中用到的,然后项目改了需求用不上了就想到用swift封装一下以后如果用得到可以借鉴下。 想看下效果图:

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.自定义一个动画视图,这个视图自己控制一个礼物数量的动画。
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 = "赠送\(model?.giftName ?? "匿名")"
}
}
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: "这就是我的名字")
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: "赠送红唇")
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: "礼物")
}()
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.礼物数量放大缩小的动画通过定时器来控制,用礼物的总数量来除一个数,这个数是每次礼物数量放大缩小动画完成后叠加的数量,知道叠加的数量等于送礼的总数量就停止动画。并且从父视图上移除。
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
}
//开始礼物数量的动画
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.自定义的视图完成后,在来考虑从左平移过来和往上平移的动画。从左平移直接用UIView的动画就可以完成,然后在往上平移这里喔考虑的是用scrollview的contentOffset来控制。每次添加一个礼物视图后往上平移一个固定的offset,然后下一个视图加进来的时候就它的y值就加上这个固定的offset。
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.最后看下调用
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":"头像","giftnum":"99","giftheadimage":"礼物1","giftusername":"不一样的烟火","giftname":"皇冠"]
let dic2 = ["userhead":"头像2","giftnum":"9","giftheadimage":"礼物2","giftusername":"简简单单","giftname":"红唇"]
self.scrollView?.addAnimationLabel(dict: dic)
self.scrollView?.addAnimationLabel(dict: dic2)
}