前段日子产品觉得满大街的Tabbar,非要整一个像系统自带的Assistive Touch类似的功能按钮来代替Tabbar的作用,无力吐槽。哎,一直在在犹豫要不要告诉产品 苹果BABA设计这个Assistive Touch真正的含义是什么啊QAQ!!
无语的是UI闷头一顿设计,图都整出来了。没办法,做呗。
趁现在项目不忙帮这个东西整理出来分享给大家。
我这边具体写一下,实现的过程。以及在实现这个东西遇到的一些坑。发现问题的童鞋要及时帮我指出哦。不要让我出糗哇!
大概
1。主要的控件组成 一个主按钮root 和 4个子按钮detail组成。
2。布局方面:考虑到这个悬浮按钮需要在左右两边子按钮针对主按钮有2套布局。可能我这种写法比较简单,带考究。我令视图的大小和主按钮的大小相同,这时候子按钮的的布局只要相对主按钮布局就可以了(不过这样会有一些响应事件的问题,下面会给出解决办法)。--简单的来说这个控件的大小是缩小之后的视图大小而非展开后后的视图大小。
主要代码实现
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)
})
}
这个比较好实现了 就是判断 endTouch的坐标和屏幕的宽度对比
2.子按钮的伸缩动画
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()
})
}
这边只列出在左边出现的情况,以及相关动画。我用的snapKit约束,只要在annimaton中设置对应的中心点。中心点的计算就是一些简单的勾股定理 sin cos相信童鞋通一眼就看出来啦。
这边要提出来的是,更新约束动画要调用self.layoutIfNeeded()
不然没有动画效果哦。。
3 要记录悬浮空间的是否处于移动状态
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
isMoiving = false
}
override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
isMoiving = true
去处理移动和点击的touch 时间。以及悬浮控件移动范围在touchend中判断
4.区分点击事件和移动事件
我在上面的root主按钮用的button,这就会导致时间被button。从而导致移动时间无法处理。
这边有2个办法
--1不用button 换成view 区分点击时间和移动时间(繁琐)
--2将button接受的时间继续往下传递
我们来看下第二种的实现,我创建了一个button的子类来处理这种有冲突的事件
class IGOSuspendButton: UIButton {
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
self.nextResponder()?.touchesBegan(touches, withEvent: event)
super.touchesBegan(touches, withEvent: event)
}
override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
self.nextResponder()?.touchesMoved(touches, withEvent: event)
super.touchesMoved(touches, withEvent: event)
}
override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
self.nextResponder()?.touchesEnded(touches, withEvent: event)
super.touchesEnded(touches, withEvent: event)
}
}
重写 父类touch的3个方法,将事件传递下去。
5.子按钮事件的响应
在开始的时候我为了布局简单,5个按钮父视图的大小我设置成了主按钮的大小。这时候展开的时候4个自按钮的就不在父视图上了。就会无法响应事件,这时候我们就需要手动指定需要响应的事件的视图
// MARK: 处理detail btn 超出父视图 不响应事件
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
}
使用
创建悬浮按钮 实现代理方法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写项目。有点慌,等项目完成,我在优化一下吧。
github地址:https://github.com/dongqihouse/DQWorkDemo/tree/master/SuspendButtonDemo