设计思路:
- 根据 titleLabel 的宽度计算 button的宽度
- 给小圆圈 添加手势
- 绘制拖动的贝塞尔曲线
- 添加炸裂效果
效果展示:
使用:
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
- 添加手势, 以及让 button 随手指的移动
let tap = UITapGestureRecognizer(target: self, action: #selector(tapBootm))
self.addGestureRecognizer(tap)
//MARK:--- 手势拖动的操作
extension QQBtn{
//开始移动的时候, 记录初始位置
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//记录按钮的初始状态
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)
}
}
}
- 绘制拖动的效果
两个圆之间的不规则的矩形的, 算法分析 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
}
- 添加爆炸效果
@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()
}
}