前段日子產(chǎn)品覺得滿大街的Tabbar,非要整一個(gè)像系統(tǒng)自帶的Assistive Touch類似的功能按鈕來代替Tabbar的作用,無力吐槽。哎,一直在在猶豫要不要告訴產(chǎn)品 蘋果BABA設(shè)計(jì)這個(gè)Assistive Touch真正的含義是什么啊QAQ!!
無語的是UI悶頭一頓設(shè)計(jì),圖都整出來了。沒辦法,做唄。
趁現(xiàn)在項(xiàng)目不忙幫這個(gè)東西整理出來分享給大家。

我這邊具體寫一下,實(shí)現(xiàn)的過程。以及在實(shí)現(xiàn)這個(gè)東西遇到的一些坑。發(fā)現(xiàn)問題的童鞋要及時(shí)幫我指出哦。不要讓我出糗哇!
大概
1。主要的控件組成 一個(gè)主按鈕root 和 4個(gè)子按鈕detail組成。
2。布局方面:考慮到這個(gè)懸浮按鈕需要在左右兩邊子按鈕針對(duì)主按鈕有2套布局??赡芪疫@種寫法比較簡(jiǎn)單,帶考究。我令視圖的大小和主按鈕的大小相同,這時(shí)候子按鈕的的布局只要相對(duì)主按鈕布局就可以了(不過這樣會(huì)有一些響應(yīng)事件的問題,下面會(huì)給出解決辦法)。--簡(jiǎn)單的來說這個(gè)控件的大小是縮小之后的視圖大小而非展開后后的視圖大小。
主要代碼實(shí)現(xiàn)
1.讓懸浮控件始終保持在屏幕兩邊
if touchPoint.x > kScreenWidth/2 {
UIView.animateWithDuration(0.2, animations: {
self.frame.origin = CGPoint(x: kScreenWidth - CGFloat(kSuspendViewWidth), y: self.touchPoint.y)
})
}else {
UIView.animateWithDuration(0.2, animations: {
self.frame.origin = CGPoint(x:0, y: self.touchPoint.y)
})
}
這個(gè)比較好實(shí)現(xiàn)了 就是判斷 endTouch的坐標(biāo)和屏幕的寬度對(duì)比
2.子按鈕的伸縮動(dòng)畫
UIView.animateWithDuration(0.3, animations: {
self.buttonRoot.transform = CGAffineTransformRotate(self.buttonRoot.transform, CGFloat(M_PI_4))
self.buttonDetail1.snp_updateConstraints { (make) in
make.center.equalTo( CGPoint(x: -kRadius , y: 0))
}
self.buttonDetail2.snp_updateConstraints { (make) in
make.center.equalTo( CGPoint(x: -kRadius * cos(M_PI/6) , y: -kRadius*cos(M_PI/3)))
}
self.buttonDetail3.snp_updateConstraints { (make) in
make.center.equalTo( CGPoint(x: -kRadius*cos(M_PI/3) , y: -kRadius*cos(M_PI/6)))
}
self.buttonDetail4.snp_updateConstraints { (make) in
make.center.equalTo( CGPoint(x:0 , y: -kRadius))
}
self.layoutIfNeeded()
})
}
這邊只列出在左邊出現(xiàn)的情況,以及相關(guān)動(dòng)畫。我用的snapKit約束,只要在annimaton中設(shè)置對(duì)應(yīng)的中心點(diǎn)。中心點(diǎn)的計(jì)算就是一些簡(jiǎn)單的勾股定理 sin cos相信童鞋通一眼就看出來啦。
這邊要提出來的是,更新約束動(dòng)畫要調(diào)用self.layoutIfNeeded()不然沒有動(dòng)畫效果哦。。
3 要記錄懸浮空間的是否處于移動(dòng)狀態(tài)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
isMoiving = false
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
isMoiving = true
去處理移動(dòng)和點(diǎn)擊的touch 時(shí)間。以及懸浮控件移動(dòng)范圍在touchend中判斷
4.區(qū)分點(diǎn)擊事件和移動(dòng)事件
我在上面的root主按鈕用的button,這就會(huì)導(dǎo)致時(shí)間被button。從而導(dǎo)致移動(dòng)時(shí)間無法處理。
這邊有2個(gè)辦法
--1不用button 換成view 區(qū)分點(diǎn)擊時(shí)間和移動(dòng)時(shí)間(繁瑣)
--2將button接受的時(shí)間繼續(xù)往下傳遞
我們來看下第二種的實(shí)現(xiàn),我創(chuàng)建了一個(gè)button的子類來處理這種有沖突的事件
class IGOSuspendButton: UIButton {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.nextResponder()?.touchesBegan(touches, withEvent: event)
super.touchesBegan(touches, withEvent: event)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.nextResponder()?.touchesMoved(touches, withEvent: event)
super.touchesMoved(touches, withEvent: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.nextResponder()?.touchesEnded(touches, withEvent: event)
super.touchesEnded(touches, withEvent: event)
}
}
重寫 父類touch的3個(gè)方法,將事件傳遞下去。
5.子按鈕事件的響應(yīng)
在開始的時(shí)候我為了布局簡(jiǎn)單,5個(gè)按鈕父視圖的大小我設(shè)置成了主按鈕的大小。這時(shí)候展開的時(shí)候4個(gè)自按鈕的就不在父視圖上了。就會(huì)無法響應(yīng)事件,這時(shí)候我們就需要手動(dòng)指定需要響應(yīng)的事件的視圖
// MARK: 處理detail btn 超出父視圖 不響應(yīng)事件
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
var view = super.hitTest(point, withEvent: event)
if view == nil {
if !self.hidden {
if CGRectContainsPoint(buttonDetail1.frame,point) {
view = buttonDetail1
}else if CGRectContainsPoint(buttonDetail2.frame,point) {
view = buttonDetail2
}else if CGRectContainsPoint(buttonDetail3.frame,point) {
view = buttonDetail3
}else if CGRectContainsPoint(buttonDetail4.frame,point) {
view = buttonDetail4
}
}
}
return view
}
使用
創(chuàng)建懸浮按鈕 實(shí)現(xiàn)代理方法CycleTabbarViewDelegate
var suspendButton: CycleTabbarView? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
suspendButton = CycleTabbarView(frame: CGRect(x: 0, y: 130, width: 60, height: 60) )
suspendButton?.delegate = self
self.view.addSubview(suspendButton!)
}
func suspendButtonsAction(type: CycleTabbarViewType) {
switch type {
case .Type1:
let alertVC = UIAlertController(title: "11", message: "22", preferredStyle: .Alert)
alertVC.addAction(UIAlertAction(title: "sure", style: .Cancel, handler: nil))
self.presentViewController(alertVC, animated: true, completion: nil)
case .Type2:
print("")
case .Type3:
print("")
case .Type4:
print("")
}
}
總體寫下來,感覺寫的還是有問題的。畢竟第一次用swift寫項(xiàng)目。有點(diǎn)慌,等項(xiàng)目完成,我在優(yōu)化一下吧。
github地址:https://github.com/dongqihouse/DQWorkDemo/tree/master/SuspendButtonDemo