2020年10月22日 星期四

swift 螢幕截圖警示語 -> xcode12

 又好久沒有跟大家分享一些小功能方法拉!

今天要跟大家分享的是用戶執行螢幕截圖時進行提醒,

例如有用戶個人基本資料畫面進行截圖,我們可能會提醒有個資外流疑慮等等...

基本上使用的方法是NotificationCenter內的原生name就可以執行了。

我們僅需寫自己想執行的selecotr動作

範例如下:

NotificationCenter.default.addObserver(self, selector: #selector(showSomeThing), name: UIApplication.userDidTakeScreenshotNotification, object: nil)

先執行觀察(監聽)動作加入,這方法可以加入在你要提醒的頁面viewdidload,記得在離開頁面時做釋放將其remove掉。

今天我是做在SceneDelegate內,主要是方便測試各個頁面等等...假如您覺得你大多數頁面都需要做這件事情就可以像我一樣寫在SceneDelegate ->  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)

如果你是舊有專案只有AppDelegate的話就直接加在

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool

接下來就是執行方法

@objc func showSomeThing() {

        let alertController = UIAlertController(title: "提醒:", message: "螢幕截圖可能會造成隱私資訊洩露", preferredStyle: .alert)

        let alertAction = UIAlertAction(title: "確定", style: .default, handler: nil)

        alertController.addAction(alertAction)

        self.window?.rootViewController?.present(alertController, animated: true, completion: nil)

    }

Selector的用法這邊我就不多做解說了,該寫哪就寫哪...


執行後的結果如下





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")

    }

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

2017年12月27日 星期三

swift4 自定義layer框線(border)

今天分享自定義layer匡線,有時候在設計上可能會有框架框線顏色兩種或三種,
但原生的通常就是讓你簡單方便,一個框架一個顏色。

下面範例就是原生整個框架顏色,我直接使用ViewController的View來給予範例如下:
self.view.layer.borderColor = UIColor.blue.cgColor;

self.view.layer.borderWidth = 10.0;

但是有時可能會需要多個label拼成一個大的並且有框架之類的時候,
又剛好只有最外圈框架顏色不同就很麻煩了,
有些人可能會選擇偷懶做一個View覆蓋在上面讓backgroundcolor是透明的,
然後給予框線並符合原本物件所需大小。

今天這邊要跟大家分享的就是寫一個CALayer的擴充來達到目的,
我建立了幾個物件,一個UILabel、一個UIButton、一個UITextField、一個UIView來呈現效果。
首先我們要先寫一個擴充如下:

extension CALayer{
    func addBorder(edge:UIRectEdge, color:UIColor, thickness:CGFloat){
        
        let borders = CALayer()
        
        switch edge {
        case .top:
            borders.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness);
            break
        case .bottom:
            borders.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness);
        case .left:
            borders.frame = CGRect(x: 0, y: 0 + thickness, width: thickness, height: frame.height - thickness * 2);
        case .right:
            borders.frame = CGRect(x: frame.width - thickness, y: 0 + thickness, width: thickness, height: frame.height - thickness * 2);
        default:
            break
        }
        
        borders.backgroundColor = color.cgColor;
        
        self.addSublayer(borders);
    }
}

這個擴充東西並不多,其實很簡短,
有人會好奇為什麼有的我會-thickness甚至做成-thickness * 2原因很簡單,
這可以依照個人喜好去做,我會做-thickness * 2 是因為那是左右兩邊,
而我不希望他有被覆蓋或是覆蓋到上或下的邊框,
所以我剪去thickness的兩倍讓他高度是去除上下邊框的高度。
但前提是你的框架寬(高)度必須是一致的。

寫好擴充後就剪得了,接下來你只要做以下範例動作就能夠產生邊框了喔!

 V1.layer.addBorder(edge: .top, color: .red, thickness: 5.0);
 V1.layer.addBorder(edge: .bottom, color: .blue, thickness: 5.0);
 V1.layer.addBorder(edge: .left, color: .green, thickness: 5.0);
 V1.layer.addBorder(edge: .right, color: .yellow, thickness: 5.0);

 btn.layer.addBorder(edge: .top, color: .brown, thickness: 2.0);
 btn.layer.addBorder(edge: .bottom, color: .gray, thickness: 2.0);
 btn.layer.addBorder(edge: .left, color: .red, thickness: 2.0);
 btn.layer.addBorder(edge: .right, color: .blue, thickness: 2.0);

 label.layer.addBorder(edge: .top, color: .black, thickness: 2.0);
 label.layer.addBorder(edge: .bottom, color: .gray, thickness: 2.0);
 label.layer.addBorder(edge: .left, color: .purple, thickness: 2.0);
 label.layer.addBorder(edge: .right, color: .orange, thickness: 2.0);

 text.layer.addBorder(edge: .top, color: .red, thickness: 2.0);
 text.layer.addBorder(edge: .bottom, color: .cyan, thickness: 2.0);
 text.layer.addBorder(edge: .left, color: .magenta, thickness: 2.0);
 text.layer.addBorder(edge: .right, color: .darkGray, thickness: 2.0);

看起來很多,是因為這種寫法就變成你每一個框都要去寫一次,
畢竟你可能四邊顏色都不同之類的,
最後附上運行出來的成果圖如下:

希望能夠幫助到有需要的朋友們!

2017年11月13日 星期一

Swift 4 將常用到的顏色製作成色塊

      我相信很多人在開發的時候都跟我一樣遇到過物件要改變顏色時美編所給的色碼都必須另外寫一段RBG或其他的方法。
      但在Swift 4(iOS11 & xCode9)出來一個新的小功能,就是自定義色塊。
      這邊就點單的說該如何製作,首先建立一個新的專案,然後選到Assets,在Assets左邊欄下方的+按下去後有一個New Color Set點選下去,如下圖:
 然後直接點選預設色塊後設定自己要的顏色,並在最上方欄位命名。

這樣完成後就能使用UIColor(named: String);
簡單一點的範例如下,我這邊為了讓大家看到改變所以做了兩個UIButton


因為這只是簡單的測試給大家看,所以程式碼也非常簡單,有些地方可以不用去執著他。只要記得當你要使用那個顏色時呼叫UIColor(named: String);即可
程式碼如下:
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var BG2: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        BG2.tintColor = UIColor.white
        touch(Btn: BG2)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func BG1(_ sender: UIButton) {
        let BG1_Color = UIColor(named: "新增的色塊");
        self.view.backgroundColor = BG1_Color
        BG2.tintColor = UIColor.white
    }
    
    @IBAction func BG2(_ sender: UIButton) {
        let BG2_Color = UIColor(named: "BG2_Color");
        self.view.backgroundColor = BG2_Color
        BG2.tintColor = UIColor.yellow
    }
    
    func touch(Btn: UIButton){
        Btn.tintColor = UIColor.blue
    }
}


執行後結果如下圖:

希望大家會喜歡,並在必要的時候善用此功能^^

2017年9月22日 星期五

關於Swfi4 使用到#selector的一些小修正

近期Apple已經釋放出正式版Xcode9雖然可以向下相容 Swift3.2
但我相信很多人會使用Swift4來進行編譯

跟以往有點不同的是這次因為有向下相容,所以原本專案是Swift3.2的話Xcode9並不會主動幫你升級成Swift4必須自己手動去調整。這邊就附上圖片給大家看一下

選擇你的prohect > targets > 專案名稱 > Build Settings > 收尋swift languae version去更改成swift4.0

好了以上是一點點的題外話,這邊主要是要說如果你在swift4中有使用#selector
在selector我們在swift3中會使用
#selector(funcName)這樣會無法像以往一樣做最簡單的方式 func xxxx(){ ... }
這樣系統會出現警告
這時不用擔心只要一個小動作,就是在func的前面加上@objc警告就會消失了唷!或是可以直接點選警告後按下Fix系統會自動幫你在該func前面帶入@objc

引述Swift3使用#selector指定的方法,只有當private時需要加上@objc,現在全部都要加上@objc