2017年8月28日 星期一

SlideMenuControllerSwift 套用分享(左邊欄)_ Swift3

今天要分享第三方套件的簡單運用,首先使用套件做個簡單教學。先至https://cocoapods.org/ 安裝cocoapods,懶惰的話可以直接下載他們的APP官方有附上抄作教學唷!很方便。

套件連結SlideMenuControllerSwift ,小弟很早以前就找到這個套件了,只是一直沒有去使用。剛好有空閒時間玩了一下。順便跟大家分享^^

首先storyboard要建立5個ViewController,並在左邊欄中加入一個UITableVew
storyboard的前置作業大致上就這樣(記得UITableView要設定delegatedataSource),還有一點要注意的是每個ViewController要記得給予Identity(storyboard ID)

接下來進入到code方面了,首先第一個要做的地方是appdelegate
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)加入以下程式碼(有些函數是擴充去寫的文中會提到)

 let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let mainViewController: MainViewController = storyboard.instantiateViewController(withIdentifier: "main") as! MainViewController
        let leftViewController: LeftViewController = storyboard.instantiateViewController(withIdentifier: "left") as! LeftViewController
        let rightViewController: RightViewController = storyboard.instantiateViewController(withIdentifier: "right") as! RightViewController
        
        let navigationController: UINavigationController = UINavigationController(rootViewController: mainViewController)
        
        leftViewController.mainViewController = navigationController
        UINavigationBar.appearance().tintColor = UIColor(hex: "689F38")
        
        let slideMenuController = ExSlideMenuController(mainViewController: navigationController, leftMenuViewController: leftViewController, rightMenuViewController: rightViewController)
        slideMenuController.automaticallyAdjustsScrollViewInsets = true
        slideMenuController.delegate = mainViewController
        slideMenuController.closeLeft()
        slideMenuController.closeRight()
        
        self.window?.backgroundColor = UIColor(red: 236.0, green: 238.0, blue: 241.0, alpha: 1.0)
        self.window?.rootViewController = slideMenuController
        self.window?.makeKeyAndVisible()


ExSlideMenuControllerUIColor(hex: String)是另外寫擴充的方法,程式碼如下

ExSlideMenuController(請例外建立一個class)
import UIKit
import SlideMenuControllerSwift

class ExSlideMenuController : SlideMenuController {

    override func isTagetViewController() -> Bool {
        if let vc = UIApplication.topViewController() {
            if vc is MainViewController ||
            vc is Test1ViewController ||
            vc is Test2ViewController {
                return true
            }
        }
        return false
    }
    
    override func track(_ trackAction: TrackAction) {
        switch trackAction {
        case .leftTapOpen:
            print("TrackAction: left tap open.")
        case .leftTapClose:
            print("TrackAction: left tap close.")
        case .leftFlickOpen:
            print("TrackAction: left flick open.")
        case .leftFlickClose:
            print("TrackAction: left flick close.")
        case .rightTapOpen:
            print("TrackAction: right tap open.")
        case .rightTapClose:
            print("TrackAction: right tap close.")
        case .rightFlickOpen:
            print("TrackAction: right flick open.")
        case .rightFlickClose:
            print("TrackAction: right flick close.")
        }   
    }

}

UIColor(hex: String)(請另外建立class或直接在想寫的地方寫擴充)
extension UIColor {

    convenience init(hex: String) {
        self.init(hex: hex, alpha:1)
    }

    convenience init(hex: String, alpha: CGFloat) {
        var hexWithoutSymbol = hex
        if hexWithoutSymbol.hasPrefix("#") {
            hexWithoutSymbol = hex.substring(1)
        }
        
        let scanner = Scanner(string: hexWithoutSymbol)
        var hexInt:UInt32 = 0x0
        scanner.scanHexInt32(&hexInt)
        
        var r:UInt32!, g:UInt32!, b:UInt32!
        switch (hexWithoutSymbol.length) {
        case 3: // #RGB
            r = ((hexInt >> 4) & 0xf0 | (hexInt >> 8) & 0x0f)
            g = ((hexInt >> 0) & 0xf0 | (hexInt >> 4) & 0x0f)
            b = ((hexInt << 4) & 0xf0 | hexInt & 0x0f)
            break;
        case 6: // #RRGGBB
            r = (hexInt >> 16) & 0xff
            g = (hexInt >> 8) & 0xff
            b = hexInt & 0xff
            break;
        default:
            // TODO:ERROR
            break;
        }
        
        self.init(
            red: (CGFloat(r)/255),
            green: (CGFloat(g)/255),
            blue: (CGFloat(b)/255),
            alpha:alpha)
    }

}
appdelegate方面大致上就完成了,接下來就是個頁面,雖然是簡易套用介面簡單,但是程式碼也不算少了,接下來一個頁面一個頁面附上code給大家參考

首先是主頁面mainViewController(記得import SlideMenuControllerSwift)
import UIKit
import SlideMenuControllerSwift

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.setNavigationBarItem()
    }


}

extension MainViewController:SlideMenuControllerDelegate{
    
    func leftWillOpen() {
        print("SlideMenuControllerDelegate: leftWillOpen")
    }
    
    func leftDidOpen() {
        print("SlideMenuControllerDelegate: leftDidOpen")
    }
    
    func leftWillClose() {
        print("SlideMenuControllerDelegate: leftWillClose")
    }
    
    func leftDidClose() {
        print("SlideMenuControllerDelegate: leftDidClose")
    }
    
    func rightWillOpen() {
        print("SlideMenuControllerDelegate: rightWillOpen")
    }
    
    func rightDidOpen() {
        print("SlideMenuControllerDelegate: rightDidOpen")
    }
    
    func rightWillClose() {
        print("SlideMenuControllerDelegate: rightWillClose")
    }
    
    func rightDidClose() {
        print("SlideMenuControllerDelegate: rightDidClose")
    }
}
//MARK: UIViewController擴充(用來建立navigationBarItem&移除)
extension UIViewController {
    
    func setNavigationBarItem() {
        self.addLeftBarButtonWithImage(UIImage(named: "ic_menu_black_24dp")!)
        self.addRightBarButtonWithImage(UIImage(named: "ic_notifications_black_24dp")!)
        self.slideMenuController()?.removeLeftGestures()
        self.slideMenuController()?.removeRightGestures()
        self.slideMenuController()?.addLeftGestures()
        self.slideMenuController()?.addRightGestures()
    }
    
    func removeNavigationBarItem() {
        self.navigationItem.leftBarButtonItem = nil
        self.navigationItem.rightBarButtonItem = nil
        self.slideMenuController()?.removeLeftGestures()
        self.slideMenuController()?.removeRightGestures()
    }

}
再來是左邊欄leftViewController
import UIKit

enum LeftMenu: Int {
    case main
    case test1
    case test2
}

protocol LeftMenuProtocol : class {
    func changeViewController(_ menu: LeftMenu)
}

class LeftViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource{

    @IBOutlet weak var leftTableView: UITableView!
   
    
    var menus = ["首頁", "test1", "test2"]
    var mainViewController: UIViewController!
    var test1ViewController: UIViewController!
    var test2ViewController: UIViewController!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        
        let mainViewController = storyboard.instantiateViewController(withIdentifier: "main") as! MainViewController
        self.mainViewController = UINavigationController(rootViewController: mainViewController)

        let test1ViewController = storyboard.instantiateViewController(withIdentifier: "test1") as! Test1ViewController
        self.test1ViewController = UINavigationController(rootViewController: test1ViewController)
        
        let test2ViewController = storyboard.instantiateViewController(withIdentifier: "test2") as! Test2ViewController
        self.test2ViewController = UINavigationController(rootViewController: test2ViewController)
        
        
        leftTableView.backgroundColor = UIColor(hex: "66ff66", alpha: 0.2)
        //隱藏多餘的cell分隔線
        leftTableView.tableFooterView = UIView()
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        //        self.view.layoutIfNeeded()
    }
    
    
    func changeViewController(_ menu: LeftMenu) {
        switch menu {
        case .main:
            self.slideMenuController()?.changeMainViewController(self.mainViewController, close: true)
        case .test1:
            self.slideMenuController()?.changeMainViewController(self.test1ViewController, close: true)
        case .test2:
            self.slideMenuController()?.changeMainViewController(self.test2ViewController, close: true)
        }
    }
    
    
    // MARK: - DataSource
    // ---------------------------------------------------------------------
    // 設定表格section的列數
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menus.count
    }
    
    // 表格的儲存格設定
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
                if cell == nil {
                    cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
                }
        cell?.backgroundColor = UIColor.lightGray
        //        cell?.imageView?.image = UIImage(named: "star")
        cell?.textLabel?.text = self.menus[indexPath.row]
        cell?.backgroundColor = UIColor.clear
        return cell!
    }
    
    // MARK: - Delegate
    // ---------------------------------------------------------------------
    // 設定cell的高度
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return self.view.frame.size.height / 10
    }
    
    // 點選儲存格事件
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let menu = LeftMenu(rawValue: indexPath.row) {
            self.changeViewController(menu)
        }
    }
    
}
public extension UITableView {
    
    func registerCellClass(_ cellClass: AnyClass) {
        let identifier = String.className(cellClass)
        self.register(cellClass, forCellReuseIdentifier: identifier)
    }
    
    func registerCellNib(_ cellClass: AnyClass) {
        let identifier = String.className(cellClass)
        let nib = UINib(nibName: identifier, bundle: nil)
        self.register(nib, forCellReuseIdentifier: identifier)
    }
    
    func registerHeaderFooterViewClass(_ viewClass: AnyClass) {
        let identifier = String.className(viewClass)
        self.register(viewClass, forHeaderFooterViewReuseIdentifier: identifier)
    }
    
    func registerHeaderFooterViewNib(_ viewClass: AnyClass) {
        let identifier = String.className(viewClass)
        let nib = UINib(nibName: identifier, bundle: nil)
        self.register(nib, forHeaderFooterViewReuseIdentifier: identifier)
    }

}
然後右邊欄rightViewController(我沒刻意寫什麼功能,如沒使用到就不要加入按鈕跟頁面即可),右邊藍什麼都不用寫...因為我沒做任何事@@

兩個子頁面是一樣的沒做任何特殊動作(Test1ViewController,Test2ViewController)
只要在ViewWillAppear加入 self.setNavigationBarItem()即可


以上希望能夠幫助到大家能夠快點上手使用SlideMenuControllerSwift的套件唷^^
在此也感謝套件作者及其他有分享教學的朋友們!

成果如下列圖片顯示:





2017年7月10日 星期一

swift3 Button單選功能

今天要來跟大家分享的是按鈕(Button)的單選效果。
參考來源http://www.cnblogs.com/luorende/p/5814597.html
有時我們可能會需要單選功能,譬如人數等等的。
而我這邊用簡單的方式製作單選功能,參考來源中作者是使用OC,而案件也是直接code寫

在此我使用storyboard來做這項功能。不多說直接附上成果圖跟code
先將storyboard做好後進行按鈕的@IBAction,注意這邊要將所有的Button拉致同一個action
並且給予tag(如下圖)
tag我個人這邊是設定101,102,103,104,105,不管怎樣不要是0且有區分即可

code方面需要寫for迴圈來判定所選到的是哪一個案件
而我的作法簡單一點,因為五個案件所以就0...4這樣就有五個值
然後因為tag我設定是101開始所以i + 101 這樣最多就是到105
做個簡單的switch來進行選到按鈕要做什麼動作或傳出什麼資料
而沒選到的另外定義一個Btn讓他取消選取,除非另外寫入限制(選到就將btn鎖定不能動作),但一般是不會去限制的。這就看個人需求了
isSelected這個Bool就是用戶是否有選取到,如果你不想用原生的也可在選到時改變自定義的選擇動作
 @IBAction func selectBtn_Single(_ sender: UIButton) {
        
        for i in 0...4  {
            if sender.tag == i + 101 {
                sender.isSelected = true
                var str:String!
                switch sender.tag {
                case 101:
                    str = ""
                case 102:
                    str = ""
                case 103:
                    str = "兔子"
                case 104:
                    str = "老鼠"
                default:
                    str = ""
                }
                singleLabel.text = "你喜歡的動物是:\(str!)"
                continue
            }
            let Btn:UIButton = self.view.viewWithTag(i + 101) as! UIButton
            Btn.isSelected = false
        }

    }

呈現出來結果如下圖
複選的寫法大致上如下(比較簡單一點),但不常使用
_ sender: UIButton
 if sender.isEnabled == true{
            sender.isEnabled = false
        }else{
            sender.isEnabled = true
        }
而更簡化的寫法就是
sender.isEnabled = !(sender.isEnabled)

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


2017年6月27日 星期二

swift3 監聽手機方向

簡單說明實作手機監聽動作,一般有時候(雖然不常)會因為手機方向而決定取用的物件貨func之類的,但要怎麼做呢?下面附上簡單的Code並實作當期改變時的動作

我的作法是自定義實作動作,我只做簡單的改變,在storybord中直接放置一個UIView,當橫向時view是藍色,直向時改變為紅色。至於constraints在這就不多說了...

 func DeviceP(){
        if UIDeviceOrientationIsPortrait(UIDevice.current.orientation){
            print("")
            self.showViewColor.backgroundColor = .red
        }else{
            print("")
            self.showViewColor.backgroundColor = .blue
        }

    }

並且在viewdidload進行監聽的動作
NotificationCenter.default.addObserver(self, selector: #selector(DeviceP), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

實際呈現結果如下圖



2017年6月6日 星期二

Swift3 UIWebView 和 WKWebView的基本運用(觸發超連結)

      今天要來講如何運用UIWebViewWKWebView的套用(讀取網頁)跟點擊後觸發要做的事情。一般新手或是因為方便也可能是習慣多數人都是使用UIWebView,而小弟我也是習慣用UIWebView,可是用過的人應該都會發現UIWebView在效能上來講並沒有比較好。又剛好某些原因需要做到觸發,於是發現了WKWebView,他效能上比UIWebView好,也是很多高手比較推薦使用的。
最下面會放上我開啟網頁的圖片,注意請使用實機測試會比較好喔!

這邊而外提一下,我所使用的網頁是利用firebase所製作出來的,所以並會停供測試的url。可能需要您自己去建立唷^^怎麼建立就不多說了,畢竟這裡主要講的是swift3

直接先附上storyboard的截圖,非常的簡單。我是為了一次呈現兩種所以做了兩個頁面給各位參考。

上圖中兩個都是ViewController,但一個有加入UIWebView

先來說UIWebView的運用吧!下面直接就附上Code並有附帶註解所以不而外做說明了

import UIKit

class WebViewController: UIViewController,UIWebViewDelegate {

    @IBOutlet weak var webView: UIWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //加入delegate因為要做觸發判斷
        webView.delegate = self
        //載入網頁
        let url = URL(string: "你的網頁位子");
        webView.loadRequest(URLRequest(url: url!))
        
    }

    //當用戶點擊觸發事件(我本身自己做的是觸發連結)
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        
        //判斷觸發的連結
        if (navigationType == .linkClicked){
            let str:String = (request.url?.scheme)!
            switch str {//利用switch判斷點擊後傳出來的url而決定動作
            case "mailto"://信箱
                //如果沒有要特地加載主旨或內容可以忽略下面內容直接跳掉開啟url即可
                let subject = "UIWebViewDome"//主旨
                let body = "這是UIWebView運用於點擊事件是發送mail"//信件內文
                let coded = "\(request)?subject=\(subject)&body=\(body)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
                //開啟信箱
                //(因為openURL前方有帶入字串"mailto:"所以系統會自動判斷開啟信箱而非safari)
                if let emailURL:URL = URL(string: coded!){
                    if UIApplication.shared.canOpenURL(emailURL){
                        UIApplication.shared.openURL(emailURL)
                    }
                }
                case "tel"://電話
                    //一般來講網頁端如果有做好就不用做下面的動作,做了其實是多餘的。除非網頁端只有提供一般電話號碼的字串並沒有帶tel:那樣的話就需要自己在做url並作下面的動作
                    
//                    let url = URL(string: (request.url?.scheme!)!)
                    let tel = "0987654321"
                    let url = URL(string: "tel:\(tel)")
                    if UIApplication.shared.canOpenURL(url!){
                        UIApplication.shared.openURL(url!)
                }
            default:
                break
            }
            
        }
        return true

    }

再來就是WKWebView這邊會多做一點說明。因為做法稍微不同
就一般新手來說使用WKWebView會感到困擾就是要都用寫的而選擇不用。
但是其實官方的教學就顯而易懂,而且不用特地在做constraints。
而我也直接用官方範例的方法寫,再參考Code裡面loadView()的內容吧!這個func會執行得比viewdidload還早唷!
注意!!!記得要import WebKit 並且宣告var webView:WKWebView! 並且加入代理人WKUIDelegate,WKNavigationDelegate

接下來就直接附上code了,一樣內有註解

import UIKit
import WebKit

@available(iOS 10.0, *)
class ViewController: UIViewController,WKUIDelegate,WKNavigationDelegate {

    var webView:WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //載入網頁
        let url = URL(string: "你的網頁位子");
        webView.load(URLRequest(url: url!))
        
    }
   
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        print("webview:\(webView) decidePolicyFornavigationAction:\(navigationAction) decisionHandler:\(decisionHandler)")
        //判斷點擊觸發事件
        switch navigationAction.navigationType {
        case .linkActivated://點擊事件
            if navigationAction.targetFrame == nil{
                self.webView.load(navigationAction.request)
            }
            let url = navigationAction.request.url
            let str:String = (url?.scheme!)!
            switch str {//判斷點擊到的事件是什麼要幹嘛
            case "mailto"://信箱
                print("mail")
                let subject = "UIWebViewDome"//主旨
                let body = "這是UIWebView運用於點擊事件是發送mail"//信件內文
                let coded = "\(navigationAction.request)?subject=\(subject)&body=\(body)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
                
                //開啟信箱
                //(因為openURL前方有帶入字串"mailto:"所以系統會自動判斷開啟信箱而非safari)
                if let emailURL = URL(string: coded!){
                    if UIApplication.shared.canOpenURL(emailURL){
                        UIApplication.shared.openURL(emailURL)
                    }
                }

                decisionHandler(.cancel)
                return
            case "tel"://電話
                //一般來講網頁端如果有做好就不用做下面的動作,做了其實是多餘的。除非網頁端只有提供一般電話號碼的字串並沒有帶tel:那樣的話就需要自己在做url並作下面的動作
                //但是!wkWebView是不管怎樣都必須要告知你要做的動作所以下面動作必須要做!
                print("tel")
              let number:String = (url?.absoluteString)!
                //因為apple一般會要求開發者在用戶做某些特定動作時必須要有提醒(例如取用相機之類的),所以在這做了一個AlertController來提醒用戶撥出通話。
                let alertController = UIAlertController(title: nil, message: "\(number.replacingOccurrences(of: "tel:", with: ""))", preferredStyle: .alert)
                alertController.addAction(UIAlertAction(title: "取消", style: .default, handler: nil));
                alertController.addAction(UIAlertAction(title: "通話", style: .default, handler: { (action:UIAlertAction) in
                    if UIApplication.shared.canOpenURL(navigationAction.request.url!){
                        UIApplication.shared.openURL(navigationAction.request.url!)
                    }
                }));
                
                
               self.present(alertController, animated: true, completion: nil)
                
            default:
                break
            }
             default:
            break
        }

        decisionHandler(.allow)

    }