方便的 UIButton 悬浮效果

2019-06-23  本文已影响0人  QuakOrigin

页面中经常遇到需要悬浮展示并且可以随手势移动的按钮,简单实现了一个。
思路就是继承 UIButton 类,然后重写拖拽方法 .touchDragInside

    addTarget(self, action: #selector(dragMoving(btn: event:)), for: .touchDragInside)
    addTarget(self, action: #selector(dragEnd(btn: event:)), for: .touchUpInside)

因为 .touchDragInside 是在手势移动过程中会不断的触发,在移动结束的手指抬起时才会触发 .touchUpInside

需要每次移动触发后获取到当前的 point

guard let touch = event.allTouches?.first else {
            print("⚠️ 无法获取 Touch ⚠️ ")
            return
        }
        
var point = touch.location(in: superview)

获取到后把 btn.center 设置为 point 所在点即可

一般会设置视图悬浮显示的区域为贴边显示,所以在滑动结束时需要重新设置下 point 的位置
不足屏幕的一半就贴在左边,否则贴在右边

 let btnx = btn.frame.size.width / 2
 if x <= btnx {
    point.x = btnx 
 }

if x >= (superview?.bounds.size.width)! - btnx {
    point.x = (superview?.bounds.size.width)! - btnx
}

由于 .touchUpInside 事件需要同时处理拖拽的结束和点击事件,所以需要每次在拖动结束后判断用户的意图是拖动视图还是点击视图,因为用户在点击的时候手指也可能在屏幕上滑动,在这里根据视图的位移来判断,定为上下左右位移超过 5px 则认为用户在进行拖动操作,否则是点击。

var p_start: CGPoint? //获取开始点击的初始位置
var isDrag: Bool?    

@objc func dragMoving(btn: UIButton, event: UIEvent) -> Void {

        var point = touch.location(in: superview)
        
        if !isDrag! { 
            p_start = point
            isDrag = true
        }
}

上面也提及到了,.touchDragInside 会随手势移动而不断的触发,我们只需要记录开始的 point 就好

在拖动结束时判断位置距离

@objc func dragEnd(btn: UIButton, event: UIEvent) -> Void {
        isDrag = false
        
        var point = touch.location(in: superview)
        let p_end = point
        
         if abs(p_start!.x - p_end.x) < 5 && abs(p_start!.y - p_end.y) < 5 {
            if (clicked != nil) {
                clicked!()
            }
        }
}

一般不需要视图紧贴屏幕边缘,会设置一个 margin 来控制离屏幕边际距离。

 let kEdgeMargin: CGFloat = 5.0  //视图与屏幕距离最小距离

最终效果:


模拟器效果

完整代码:FlyBtn

上一篇下一篇

猜你喜欢

热点阅读