2018年10月28日 星期日

UIButton倒數計時並開啟觸發

有時候有些小功能可能需要倒數計時後才能在觸發,例如簡訊驗證碼發送。要避免伺服器一直重複處理同一個門號發送,所以我們可能再送出後限制一分鐘後才能重新發送,這時就需要倒數計時顯示給用戶看並且是無法觸發的。
這功能不會太複雜所以我也不細說直些附上完整的程式碼跟git連結
https://github.com/h81061678/Button-countdown

貼心小提醒,UIButton的Type要設定為Custom,這樣數字再變更時才不會有閃爍的問題


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var sendButton: UIButton!
    var timeStop:Int!
    var timer:Timer?
    var counter = 20
    
    override func viewDidLoad() {
        super.viewDidLoad()
        sendButton.layer.cornerRadius = 5;
        label.text = "還沒處發";
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if self.timer != nil{
            self.timer?.invalidate()
        }
    }
    
    func timerEanbled(){
        sendButton.backgroundColor = UIColor(named: "reColor");
        sendButton.layer.borderWidth = 2
        sendButton.layer.borderColor = UIColor.red.cgColor
        self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(resendButton), userInfo: nil, repeats: true)
    }
    
    @objc func resendButton(){
        if (counter > 1){
            counter = counter - 1
            label.text = "已觸發";
            sendButton.setTitle(" 於\(counter)秒後可觸發 ", for: .normal)
        }else{
            label.text = "可重新觸發";
            sendButton.layer.borderWidth = 0
            sendButton.isEnabled = true
            sendButton.setTitleColor(.white, for: .normal)
            sendButton.backgroundColor = UIColor(named: "myColor");
            self.timer?.invalidate()
            sendButton.setTitle("重新發送", for: .normal)
            counter = 20
        }
    }

    @IBAction func sendAction(_ sender: UIButton) {
        sendButton.isEnabled = false;
        self.timerEanbled()
    }
    
}


封裝UIAlertController成為Extension

每次使用AlertController都要寫個好幾行是不是覺得很煩躁呢?
又或者要使用時沒有顯示問題?
通常要present一個Alert的前提是要在當前最上方的ViewController,今天我來分享我寫的Extension讓大家參考。

首先我會建立三個新的文件檔並且impotr UIKit ,您也可以只建立一個文件檔即可。
然後最先要處理的是取得當前最上方的ViewController

extension UIViewController {
    //取得當前uiviewcontroller
    class func getCurrentVC() -> UIViewController?{
        var result:UIViewController?
        var window = UIApplication.shared.keyWindow
        if window?.windowLevel != UIWindow.Level.normal{
            let windows = UIApplication.shared.windows
            for tmpWin in windows{
                if tmpWin.windowLevel == UIWindow.Level.normal{
                    window = tmpWin
                    break
                }
            }
        }
        let fromView = window?.subviews[0]
        if let nextRespnder = fromView?.next{
            if nextRespnder.isKind(of: UIViewController.self){
                result = nextRespnder as? UIViewController
            }else{
                result = window?.rootViewController
            }
        }
        return result
    }

}

再來就可以進行UIAlertController及UIAlertAction的Extension 如下:

extension UIAlertController {
    class func  showAlertController(title:String,msg:String,style:UIAlertController.Style,actions:[UIAlertAction]) {
        let VC = UIViewController.getCurrentVC()
        let alertController = UIAlertController(title: title, message: msg, preferredStyle: style);
        for action in actions{
            alertController.addAction(action)
        }
        
        VC?.present(alertController, animated: true, completion: nil);
    }
    

}

我故意將UIAlertAction封裝成一個Array,並讓他跑for迴圈去加入AlertController,因為每次需求都不同,可能只需要一個Action,有時需要兩個或以上的Action,所以使用Array搭配for迴圈就可以輕鬆許多。

extension UIAlertAction {
    class func addAction(title:String,style:UIAlertAction.Style,handler:((UIAlertAction) -> Void)?) -> UIAlertAction{
        let alertAction = UIAlertAction(title: title, style: style, handler: handler);
        return alertAction
    }

}

你可能會好奇為什麼style為什麼不寫死,因為顧慮到每個不同需求時可能會使用不同的style所以這方法跟官方所提供沒有太大差別,但會比原本寫官方的簡化許多。
而Action其實就只有在用到時宣告並呼叫就能夠使用了,下方附上呼叫時的程式碼。
請自行寫個Button去觸發執行


 let one = UIAlertAction.addAction(title: "oneAction", style: .default) {
            (action) in
            print("one")
        }
        let two = UIAlertAction.addAction(title: "twoAction", style: .default) {
            (action) in
            print("two")
        }
        let cancel = UIAlertAction.addAction(title: "cancel", style: .cancel) {
            (action) in
            print("cencel")
        }
        let actions = [one,two,cancel];
        

       UIAlertController.showAlertController(title: "展示", msg: "三個Action的實作", style: .alert, actions: actions)

最後效果如下

希望能夠幫助到有需要用到的朋友們
範例https://github.com/h81061678/AlertController_Extension
另附上OC版https://github.com/h81061678/OC_AlertController_Extension

2018年3月14日 星期三

UIView & UIImageView 的點擊觸發事件 Swift4

有一段時間沒記錄小功能分享了,今天要分享的是觸發事件。
我想很多新手或是想偷懶的時候在某些特定畫面上會放一個無色無味的UIButton
至少目的有達到....其實也沒什麼不好。
但是本身有觸發事件,學起來對自己是有好處的^^
如果大家有印象我之前有寫過鍵盤監聽(網誌:前往觀看

今天就不附上SotryBoard的畫面了,因為這只是簡單的小分享。

原理其實很簡單,一樣是使用UITapGestureRecognizer

先來說明UIView的使用,不管你是用storyboard拉的outlet還是程式碼建立方法都一樣
我這邊適用storyboard做的,就麻煩自己稍微思考摟^^
首先建立UITapGestureRecognizer

let MyTouch = UITapGestureRecognizer()
        MyTouch.addTarget(self, action: #selector(myView_Touch))

當然你也可以這樣寫(比較聰明一點)

let myViewTouch = UITapGestureRecognizer(target: self, action: #selector(myView_Touch));

別忘了將觸發方法加入,讓UIView知道自己有這個功能

self.myView.addGestureRecognizer(myViewTouch);

selector裡面當然就是你自己定義觸發的方法
@objc func myView_Touch(){
        print("點擊了view")

    }


接下來是UIImageView,在ImageView這邊要記得多寫一行...

 myImage.isUserInteractionEnabled = true
主要是讓用戶可以進行變更或動作(互動)
大家可能會好奇為什麼UIView可以不用寫,因為UIView本身默認是true
但UIImageView跟UILable的默認是false所以要加這行上去,讓他知道我們是要能互動的
剩下的寫法都跟UIView一樣,我就一次貼上來給大家參考

  let myImageTouch = UITapGestureRecognizer(target: self, action: #selector(myImage_Touch));
        myImage.isUserInteractionEnabled = true

        self.myImage.addGestureRecognizer(myImageTouch);

 @objc func myImage_Touch(){
        print("點擊了image")

    }

希望這多少有幫助到需要的朋友們