iOS 仿qq消息拖動動畫(swift 版)

設(shè)計思路:

  1. 根據(jù) titleLabel 的寬度計算 button的寬度
  2. 給小圓圈 添加手勢
  3. 繪制拖動的貝塞爾曲線
  4. 添加炸裂效果

效果展示:

123.gif

使用:

func setBtn()  {
    //設(shè)置粘性的最長距離
    //小球的背景顏色
    //字體的顏色
    //距離超多多長, 可炸裂
    //位置
    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<UITouch>, with event: UIEvent?) {
    //記錄按鈕的初始狀態(tài)
    btnSuperview = self.superview
    
    rect = self.convert(self.bounds, to: keyWindow)
    
}

//讓小圓圈隨著 手勢拖動 移動
override func touchesMoved(_ touches: Set<UITouch>, 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<UITouch>, 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. 繪制拖動的效果
    兩個圓之間的不規(guī)則的矩形的, 算法分析 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()
    }
    
}

代碼下載

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容