iOS 仿qq消息拖动动画(swift 版)

设计思路:

  1. 根据 titleLabel 的宽度计算 button的宽度
  2. 给小圆圈 添加手势
  3. 绘制拖动的贝塞尔曲线
  4. 添加炸裂效果

效果展示:

iOS 仿qq消息拖动动画(swift 版)_第1张图片
123.gif

使用:

func setBtn()  {
    //设置粘性的最长距离
    //小球的背景颜色
    //字体的颜色
    //距离超多多长, 可炸裂
    //位置
    let qqButton = QQBtn(buttonOption: QQButtonOptions(distance: 150.0, buttonBackColor: UIColor.magenta, titleColor: UIColor.white, disappearDistance: 200.0, center: CGPoint(x: self.bounds.width - 50, y: 20)))
    qqButton.count = String(arc4random() % 1000)
    contentView.insertSubview(qqButton, at: 0)
    
}

代码展示
1.计算 button 的宽度

let myString: NSString = count as NSString
let size: CGSize = myString.size(withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17.0)]);            backgroundColor = option.buttonBackColor
self.bounds.size = CGSize(width: size.width + 10, height: size.height)

layer.cornerRadius = size.height / 2.0
layer.masksToBounds = true
  1. 添加手势, 以及让 button 随手指的移动
let tap = UITapGestureRecognizer(target: self, action: #selector(tapBootm))
self.addGestureRecognizer(tap)

//MARK:--- 手势拖动的操作
extension QQBtn{

//开始移动的时候, 记录初始位置
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
    //记录按钮的初始状态
    btnSuperview = self.superview
    
    rect = self.convert(self.bounds, to: keyWindow)
    
}

//让小圆圈随着 手势拖动 移动
override func touchesMoved(_ touches: Set, with event: UIEvent?){
    for touch: AnyObject in touches {
        let t: UITouch = touch as! UITouch
        //获取当前手势的中心点, 赋值给当前的控件
        self.center = t.location(in: keyWindow)
        keyWindow.addSubview(self)
        
        let x = rect.origin.x + rect.width / 2 - self.center.x
        let y = rect.origin.y + rect.height / 2 - self.center.y
        
        
        moveDistance = sqrt(x * x + y * y)
        scal = (option.distance - moveDistance) / option.distance
        if moveDistance > option.distance || scal < 0.2{
            shapeLayer.path = nil
            circleLayer.path = nil
        }else{
           
            setCircleLayer()
            setCirCle()
            
        }
        
    }
}

//松手的时候
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
    
    //keyWindow 移除当前的
    guard moveDistance < option.disappearDistance else {
        setBoomImage(str: "move")
        
        return
    }
    self.circleLayer.path = nil
    self.shapeLayer.path = nil
    //重新添加到 cell 上
    UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [.allowUserInteraction,.beginFromCurrentState], animations: {
        //在 keyWindow上的位置
        self.center = CGPoint(x: self.rect.origin.x + self.rect.width / 2, y: self.rect.origin.y + self.rect.height / 2)
    }) { (finished) in
        //在父视图上的位置
        self.center = self.option.center
        self.btnSuperview?.addSubview(self)
        
    }

}

}

  1. 绘制拖动的效果
    两个圆之间的不规则的矩形的, 算法分析 http://blog.csdn.net/xieyupeng520/article/details/50374561
 func setCirCle() {
    var cosDigree: CGFloat!
    var sinDigree: CGFloat!
    
    let x1: CGFloat = self.center.x
    let y1:CGFloat = self.center.y
    let x2:CGFloat = rect.origin.x + rect.width / 2.0
    let y2:CGFloat = rect.origin.y + rect.height / 2.0
    let x3: Float = Float((x2 - x1) * (x2 - x1))
    let y3: Float = Float((y2 - y1) * (y2 - y1))
    let centerDistance: CGFloat = CGFloat(sqrtf(x3 + y3))
    if centerDistance == 0 {
        cosDigree = 1;
        sinDigree = 0;
    }else{
        cosDigree = (y2 - y1) / centerDistance
        sinDigree = (x2 - x1) / centerDistance
    }
    let r1:CGFloat =  self.bounds.height / 2 - 5
    let r2 = rect.height * scal / 2
    let pointA = CGPoint(x: x1 - r1 * cosDigree, y: y1 + r1 * sinDigree)
    let pointB = CGPoint(x: x1 + r1 * cosDigree, y: y1 - r1 * sinDigree)
    let pointD = CGPoint(x: x2 - r2 * cosDigree!, y: y2 + r2 * sinDigree)
    let pointC = CGPoint(x: x2 + r2 * cosDigree!, y: y2 - r2 * sinDigree)
    let pointO = CGPoint(x: pointA.x + (centerDistance / 2) * sinDigree, y: pointA.y + (centerDistance / 2) * cosDigree)
    let pointP = CGPoint(x: pointB.x + (centerDistance / 2) * sinDigree, y: pointB.y + (centerDistance / 2) * cosDigree)
    
    
    let be = UIBezierPath()
    be.move(to: pointA)

    be.addQuadCurve(to: pointD, controlPoint: pointO)
    be.addLine(to: pointC)
    be.addQuadCurve(to: pointB, controlPoint: pointP)
    
    shapeLayer.path = be.cgPath

}
  1. 添加爆炸效果
@objc func setBoomImage(str: String)  {
    
    self.isHidden = true
    let imageView = UIImageView(frame: self.frame)
    
    let imageArray = NSMutableArray(capacity: 2)
    for i in 1..<5 {
        let image = UIImage(named: "unreadBomb_\(i)")
        imageArray.add(image!)
    }
    imageView.animationImages = imageArray as? [UIImage]
    imageView.animationDuration = 0.5
    imageView.animationRepeatCount = 1
    imageView.startAnimating()
    if str == "tap" {
        self.superview?.addSubview(imageView)
    }else{
        keyWindow.addSubview(imageView)
    }
    
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
        imageView.removeFromSuperview()
    }
    
}

代码下载

你可能感兴趣的:(iOS 仿qq消息拖动动画(swift 版))