Swift - 懸浮圖標+GIF(轉) 轉

import UIKit
// 聲明協議
protocol FloatDelegate {
    func singleClick()
    
    func repeatClick()
}

class TouchButton: UIButton {
    
    // 是否可拖拽
    var isDragEnable: Bool = true
    
    // 拖拽後是否自動移到邊緣
    var isAbsortEnable: Bool = true
    
    // 背景顏色
    var bgColor: UIColor? = UIColor.red
    
    // 正常情況下 透明度
    var alphaOfNormol: CGFloat = 1.0
    
    // 拖拽時的透明度
    var alphaOfDrag: CGFloat = 1.0
    
    // 圓角大小
    var radiuOfButton: CGFloat = 12
    
    // 拖拽結束後的等待時間
    var timeOfWait: CGFloat = 1.5
    
    // 拖拽結束後的過渡動畫時間
    var timeOfAnimation: CGFloat = 0.3
    
    // 按鈕距離邊緣的內邊距
    var paddingOfbutton: CGFloat = 2
    
    // 代理
    var delegate: FloatDelegate? = nil
    
    // 計時器
    fileprivate var timer: Timer? = nil
    
    // 內部使用 起到數據傳遞的作用
    fileprivate var allPoint: CGPoint? = nil
    
    // 內部使用
    fileprivate var isHasMove: Bool = false
    
    fileprivate var isFirstClick: Bool = true
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = self.bgColor
        self.alpha =  self.alphaOfNormol
        self.layer.cornerRadius = self.radiuOfButton
        self.addTarget(self, action: #selector(singleClick), for: .touchUpInside)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.alpha = self.alphaOfDrag
        // 計時器取消
        self.timer?.invalidate()
        // 不可拖拽則退出執行
        if !isDragEnable {
            return
        }
        self.allPoint = touches.first?.location(in: self)
        if touches.first?.tapCount == 1  {
            self.perform(#selector(singleClick), with: nil, afterDelay: 0.2)
        } else if touches.first?.tapCount == 2 {
            self.perform(#selector(repeatClick))
        }
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.isHasMove = true
        if self.isFirstClick {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(singleClick), object: nil)
            self.isFirstClick = false
        }
        if !isDragEnable {
            return
        }
        let temp = touches.first?.location(in: self)
        // 計算偏移量
        let offsetx = (temp?.x)! - (self.allPoint?.x)!
        let offsety = (temp?.y)! - (self.allPoint?.y)!
        self.center = CGPoint.init(x: self.center.x + offsetx, y: self.center.y + offsety)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.isFirstClick = true
        if #available(iOS 10.0, *) {
            self.timer = Timer.init(timeInterval: TimeInterval(self.timeOfWait), repeats: false, block: { (Timer) in
                // 過渡
                UIView.animate(withDuration: TimeInterval(self.timeOfAnimation), animations: {
                    self.alpha = self.alphaOfNormol
                })
            })
        } else {
            // 過渡
            UIView.animate(withDuration: TimeInterval(self.timeOfAnimation), animations: {
                self.alpha = self.alphaOfNormol
            })        }
        // 這段代碼只有在按鈕移動後才需要執行
        if self.isHasMove && isAbsortEnable && self.superview != nil {
            // 移到父view邊緣
            let marginL = self.frame.origin.x
            let marginT = self.frame.origin.y
            let superFrame = self.superview?.frame
            let tempy = (superFrame?.height)! - 2 * self.frame.height - self.paddingOfbutton
            let tempx = (superFrame?.width)! - self.frame.width - self.paddingOfbutton
            let xOfR = (superFrame?.width)! - self.frame.width - self.paddingOfbutton
            UIView.animate(withDuration: 0.2, animations: {
                var x = self.frame.origin.x
                if marginT < self.frame.height + self.paddingOfbutton {
                    // 靠頂部
                    if x > tempx {
                        x = tempx
                    }
                    if x < self.paddingOfbutton {
                        x = self.paddingOfbutton
                    }
                    
                    self.frame = CGRect.init(x: x, y: self.paddingOfbutton, width: self.frame.width, height: self.frame.height)
                    
                } else if marginT > tempy {
                    // 靠底部
                    if x > tempx {
                        x = tempx
                    }
                    if x < self.paddingOfbutton {
                        x = self.paddingOfbutton
                    }
                    let y = tempy + self.frame.height - (812 == 812.0 ? 34.0 + 49.0 : 49.0)
                    self.frame = CGRect.init(x: x, y: y, width: self.frame.width, height: self.frame.height)
                } else
                    if marginL > ((superFrame?.width)! / 2) {
                    // 靠右移動
                    self.frame = CGRect.init(x: xOfR, y: marginT, width: self.frame.width, height: self.frame.height)
                } else {
                    // 靠左移動
                    self.frame = CGRect.init(x: self.paddingOfbutton, y: marginT, width: self.frame.width, height: self.frame.height)
                }
            })
        }
        self.isHasMove = false
        // 將計時器加入runloop
        if let temptime = self.timer {
            RunLoop.current.add(temptime, forMode: .commonModes)
        }
    }
    
    @objc func singleClick() {
        self.delegate?.singleClick()
    }
    
    @objc func repeatClick() {
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(singleClick), object: nil)
        self.delegate?.repeatClick()
    }
    


}

以上是懸浮圖標的主要代碼

import UIKit
import ImageIO
import MobileCoreServices

class ViewController: UIViewController ,FloatDelegate{


    override func viewDidLoad() {
        super.viewDidLoad()
        let frame = CGRect.init(x: 3, y: 100, width: 90, height: 80)
        let allbutton = TouchButton.init(frame: frame)
        allbutton.delegate = self
        allbutton.backgroundColor = UIColor.clear
        let (images,dur) = showGif()!
        allbutton.setImage(UIImage.animatedImage(with: images, duration: dur), for: .normal)
        allbutton.alphaOfDrag = 1
        allbutton.alphaOfNormol = 1
        self.view.addSubview(allbutton)
        
        allbutton.imageView?.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.aa(g:)))
        tap.numberOfTapsRequired = 1
        //        tap.numberOfTouchesRequired = 1
        allbutton.addGestureRecognizer(tap)
        
        let frame2 = CGRect.init(x: 3, y: 300, width: 60, height: 60)
        let allbutton2 = TouchButton.init(frame: frame2)
        // 拖拽後不能回到邊緣
        allbutton2.isAbsortEnable = false
        allbutton2.backgroundColor = UIColor.black
        self.view.addSubview(allbutton2)

    }
    

    func singleClick() {
        print("單擊")
    }
    
    func repeatClick() {
         print("雙擊")
    }
    @objc func aa(g:UITapGestureRecognizer) {
        print("aa")
        
    }

    private func showGif() ->([UIImage], TimeInterval)? {
        let path = Bundle.main.path(forResource: "sf", ofType: "gif")
        let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: path!))
        let source = CGImageSourceCreateWithData(data! as CFData, nil)
        let count = CGImageSourceGetCount(source!)
        let options: NSDictionary = [kCGImageSourceShouldCache as String: true, kCGImageSourceTypeIdentifierHint as String: kUTTypeGIF]
        var gifDuration = 0.0
        var images = [UIImage]()
        
        func frameDuration(from gifInfo: NSDictionary) -> Double {
            let gifDefaultFrameDuration = 0.100
            let unclampedDelayTime = gifInfo[kCGImagePropertyGIFUnclampedDelayTime as String] as? NSNumber
            let delayTime = gifInfo[kCGImagePropertyGIFDelayTime as String] as? NSNumber
            let duration = unclampedDelayTime ?? delayTime
            guard let frameDuration = duration else { return gifDefaultFrameDuration }
            
            return frameDuration.doubleValue > 0.011 ? frameDuration.doubleValue : gifDefaultFrameDuration
        }
        for i in 0 ..< count {
            guard let imageRef = CGImageSourceCreateImageAtIndex(source!, i, options) else {
                return nil
            }
            if count == 1 {
                //只有一張圖片時
                gifDuration = Double.infinity//無窮大
            }else {
                // Animated GIF
                guard let properties = CGImageSourceCopyPropertiesAtIndex(source!, i, nil), let gifinfo = (properties as NSDictionary)[kCGImagePropertyGIFDictionary as String] as? NSDictionary  else {
                    return nil
                }
                gifDuration += frameDuration(from: gifinfo)
            }
            images.append(UIImage.init(cgImage: imageRef, scale: UIScreen.main.scale, orientation: .up))
        }
        return (images, gifDuration)
    }

    
}

由於本人在測試點擊事件時存在點擊有bug的情況,從而在按鈕的image上加了手勢事件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章