顯示具有 Swift 標籤的文章。 顯示所有文章
顯示具有 Swift 標籤的文章。 顯示所有文章

2018年8月2日 星期四

iOS Swift 信用卡 Credit Card

使用套件
Braintree可以快速使用
但是目前還是測試階段的樣子
 
基本流程就是 
1.先取得Token(自己的server 這裡用官方測試提供的)
2.再將Token丟給braintree server
3.取得Nonce再丟給自己的server註冊
4.然後自己server再跟braintree server溝通

這邊提供iOS手機端方法

在Podfile加入 
pod 'BraintreeDropIn'
下載套件完成後在storyboard拉個有按鈕的UI
Ex:
Braintree有提供測試用的信用卡號
可來這裡參考 
https://developers.braintreepayments.com/reference/general/testing/ruby
 
在ViewController.swift

import UIKit
import BraintreeDropIn
import Braintree

class ViewController: UIViewController {

    @IBOutlet weak var btnShow: UIButton!
    @IBOutlet weak var indicator: UIActivityIndicatorView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

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

    func fetchClientToken() {
        self.btnShow.isEnabled = false
        self.indicator.isHidden = false
        // TODO: Switch this URL to your own authenticated API
        // 測試用官方取得Token Url
        let clientTokenURL = NSURL(string: "https://braintree-sample-merchant.herokuapp.com/client_token")!
        let clientTokenRequest = NSMutableURLRequest(url: clientTokenURL as URL)
        clientTokenRequest.setValue("text/plain", forHTTPHeaderField: "Accept")
        
        URLSession.shared.dataTask(with: clientTokenRequest as URLRequest) { (data, response, error) -> Void in
            // TODO: Handle errors
            let clientToken = String(data: data!, encoding: String.Encoding.utf8)
            print("clientToken:\(clientToken!)")
            self.showDropIn(clientTokenOrTokenizationKey: clientToken!)
            
            // As an example, you may wish to present Drop-in at this point.
            // Continue to the next section to learn more...
            }.resume()
    }

    @IBAction func jumpDropIn(_ sender: UIButton) {
        fetchClientToken()
    }
    
    
    func showDropIn(clientTokenOrTokenizationKey: String) {
        DispatchQueue.main.async {
        let request =  BTDropInRequest()
        let dropIn = BTDropInController(authorization: clientTokenOrTokenizationKey, request: request) { (controller, result, error) in
            if (error != nil) {
                print("ERROR:\(error.debugDescription)")
            } else if (result?.isCancelled == true) {
                print("CANCELLED")
            } else if let result = result {
                // Use the BTDropInResult properties to update your UI
                print("result paymentOptionType:\(result.paymentOptionType)")
                // 取得nonce後,拿nonce去後端註冊
                print("result paymentMethod.nonce:\(result.paymentMethod!.nonce)")
                print("result paymentIcon:\(result.paymentIcon)")
                print("result paymentDescription:\(result.paymentDescription)")
            }
            
                self.btnShow.isEnabled = true
                self.indicator.isHidden = true
            controller.dismiss(animated: true, completion: nil)
        }
        self.present(dropIn!, animated: true, completion: nil)
        }
    }
}





2017年8月21日 星期一

iOS Swift Multiple Language Localizable 切換多語系

不是認手機語系, 而是直接在app上切換語系

1.在Main.storyboard 拉三個按鈕與一個Label


2.與ViewController.swift建立連接
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var labMessage: UILabel!
    

    override func viewDidLoad() {
        super.viewDidLoad()
    }

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

    @IBAction func btnEnglish(_ sender: UIButton) {
        UserDefaults.standard.set("Base", forKey: "lang") //儲存語系為基本
        setMessage()
    }
    
    @IBAction func btnJapan(_ sender: UIButton) {
        UserDefaults.standard.set("ja", forKey: "lang") //儲存語系為日文
        setMessage()
    }
    
    @IBAction func btnChinses(_ sender: UIButton) {
        UserDefaults.standard.set("zh-Hant", forKey: "lang") //儲存語系為繁體中文
        setMessage()
    }
    
    func setMessage() {
        labMessage.text = "A Song of Ice and Fire".localized //使用擴展功能 localized
    }

}

extension String{

    var localized: String {
                
        let lang = UserDefaults.standard.string(forKey: "lang")
        
        let bundle = Bundle(path: Bundle.main.path(forResource: lang, ofType: "lproj")!)

        return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
        
    }
}

3.建立Localizable.strings檔案
New File... -> 找到 String File  -> 輸入Localizable.strings -> Create
建立完成後點選檔案->右邊的 ->再點選Localize...

4.回到PROJECT的Info 點選Localizations的 + 會出現所有語言, 這裡選擇Japanese(ja)與Chinses(zh-Hant), 括弧內為設定文字對應的縮寫

勾選建立的Localizable.strings就好

 接著Localizable.strings會出現三個檔案

分別在 Localizable.strings(Base)輸入
"A Song of Ice and Fire" = "A Song of Ice and Fire";

Localizable.strings(Japanese)輸入
"A Song of Ice and Fire" = "氷と炎の歌";

Localizable.strings(Chinese(Traditional))輸入
"A Song of Ice and Fire" = "冰與火之歌"; 





檔案下載:
https://github.com/terryyamg/MultipleLanguageTest
參考連結:
https://stackoverflow.com/questions/25081757/whats-nslocalizedstring-equivalent-in-swift
https://medium.com/lean-localization/ios-localization-tutorial-938231f9f881

2017年8月10日 星期四

iOS Swift Cache Image 簡易的Image Cache

簡單的Cache Image, 讓圖片不用一直下載,造成卡卡的問題

1.建立一個Project, 先在Info.plist ->右鍵 Open AS -> 選Source Code
在dict內加入,
NSAppTransportSecurity
NSAllowsArbitraryLoads 

2.接著建立MyTableViewCell.swift, 後面在Cell建立Image View後拉過來對應
class MyTableViewCell: UITableViewCell {

    @IBOutlet weak var iv: UIImageView!
    
    var ivUrl: NSURL! //圖片來源url
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

3.然後在Main.storyboard拉一個Table View

在cell裡面加個Image View, 對應Class: MyTableViewCell
Table View拉一下dataSource與delegate到ViewController
記得給Cell的Identifier,這裡寫ImageCell

4.建立一個CustomImageCache.swift檔案
import UIKit

class CustomImageCache {
    
    static let sharedCache: NSCache = { () -> NSCache<AnyObject, AnyObject> in
        let cache = NSCache<AnyObject, AnyObject>()
        cache.name = "MyImageCache"
        cache.countLimit = 20 // Max 20 images in memory.
        cache.totalCostLimit = 10*1024*1024 // Max 10MB used.
        return cache
    }()
    
}

extension NSURL {
    
    typealias ImageCacheCompletion = (UIImage) -> Void
    
    
    var cachedImage: UIImage? {
        return CustomImageCache.sharedCache.object(
            forKey: absoluteString as AnyObject) as? UIImage
    }
    
    func fetchImage(completion: @escaping ImageCacheCompletion) {
        // 如果需要客製化取得資料在此做
        let task = URLSession.shared.dataTask(with: self as URL) {
            data, response, error in
            if error == nil {
                if let data = data, let image = UIImage(data: data) {
                    CustomImageCache.sharedCache.setObject(
                        image,
                        forKey: self.absoluteString as AnyObject,
                        cost: data.count)
                    DispatchQueue.main.async() {
                        completion(image)
                    }
                }
            }
        }
        task.resume()
    }
    
}

5.最後在ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var url = [String]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 重複50張圖片
        url = Array(repeating: "http://g03.a.alicdn.com/kf/HTB1hvNUIFXXXXbBXFXXq6xXFXXX2/3D-Diamond-Embroidery-Paintings-Rhinestone-Pasted-diy-Diamond-painting-cross-Stitch-font-b-coffe-b-font.jpg", count: 50)
    }

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

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return url.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ImageCell") as! MyTableViewCell
        let ivUrl = NSURL(string: url[indexPath.row])
    
        cell.ivUrl = ivUrl // For recycled cells' late image loads.
        if let image = ivUrl?.cachedImage { //抓過了 -> 直接顯示
            cell.iv.image = image
            cell.iv.alpha = 1
        } else { //沒抓過 ->下載圖片
            cell.iv.alpha = 0
            // 下載圖片
            ivUrl?.fetchImage { image in
                // Check the cell hasn't recycled while loading.
                if cell.ivUrl == ivUrl {
                    cell.iv.image = image
                    UIView.animate(withDuration: 0.3) {
                        cell.iv.alpha = 1
                    }
                }
            }
        }
        
        return cell
    }
}



檔案下載:
https://github.com/terryyamg/CacheImag
參考來源:
http://www.splinter.com.au/2015/09/24/swift-image-cache/

2017年7月1日 星期六

iOS Swift Custom View Xib 客製化 視窗

建立一個上下左右跑進來的視窗,使用xib客製化元件

1.建立一個xib檔案 File -> New -> File ... 選擇View
2.MyView.xib


a.建立 MyView.xib 並拉一個Label到視窗
b.選擇View
c.設定屬性Size:Freeform 其他None

3.建立MyView.Swift
//
//  MyView.swift
//  JumpViewTest
//
//  Created by Terry Yang on 2017/6/30.
//  Copyright © 2017年 terryyamg. All rights reserved.
//

import UIKit

class MyView: UIView {
    
    @IBOutlet weak var labCustom: UILabel!
    
    var view:UIView!
    
    // Label Inspectable
    @IBInspectable
    var mytitleLabelText: String? {
        get {
            return labCustom.text
        }
        set(mytitleLabelText) {
            labCustom.text = mytitleLabelText
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    func setup() {
        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [
            UIViewAutoresizing.flexibleWidth,
            UIViewAutoresizing.flexibleHeight
        ]
        addSubview(view)
    }
    
    func loadViewFromNib() -> UIView {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: "MyView", bundle: bundle)
        let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
        
        return view
    }
    
}

4.在MyView.xib

a.選擇File;s Owner
b.點擊Identity並選擇Class 對應到 MyView

5.連結Label到MyView.swift
6.於Main.storyboard建立四個按鈕

7.ViewController.swift


//
//  ViewController.swift
//  JumpViewTest
//
//  Created by Terry Yang on 2017/6/30.
//  Copyright © 2017年 terryyamg. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    var indexOfTop : Int    = 0
    var indexOfLeft : Int   = 0
    var indexOfRight : Int  = 0
    var indexOfBottom : Int = 0
    
    var topView : MyView?
    var leftView : MyView?
    var rightView : MyView?
    var bottomView : MyView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //  Top 按鈕
    @IBAction func btnShowTop(_ sender: UIButton) {
        indexOfTop += 1
        
        if topView == nil {
            //建立客製化View視窗
            topView = MyView(frame: CGRect(x: 0, y: -150, width: UIScreen.main.bounds.size.width, height: 150)) //設定初始位置與大小
            topView?.backgroundColor = .red //背景顏色
            topView?.labCustom.text = "Oh! Top View" //顯示文字
            self.view.addSubview(topView!) //加入此視窗
        }
        
        if indexOfTop % 2 == 1 { //點擊展開視窗
            UIView.animate(withDuration: 0.5, animations: {
                self.topView?.frame.origin.y += 150
            }, completion: nil)
        } else { //點擊收起視窗
            UIView.animate(withDuration: 0.5, animations: {
                self.topView?.frame.origin.y -= 150
            }, completion: nil)
        }
    }
    
    // Left 按鈕
    @IBAction func btnShowLeft(_ sender: UIButton) {
        
        indexOfLeft += 1
        
        if leftView == nil {
            leftView = MyView(frame: CGRect(x: -150, y: 0, width: 150, height: UIScreen.main.bounds.size.height))
            leftView?.backgroundColor = .brown
            leftView?.labCustom.text = "It's Left"
            self.view.addSubview(leftView!)
        }
        
        if indexOfLeft % 2 == 1 {
            UIView.animate(withDuration: 0.5, animations: {
                self.leftView?.frame.origin.x += 150
            }, completion: nil)
        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.leftView?.frame.origin.x -= 150
            }, completion: nil)
        }
        
    }
    
    // Right 按鈕
    @IBAction func btnShowRight(_ sender: UIButton) {
        
        indexOfRight += 1
        
        if rightView == nil {
            rightView = MyView(frame: CGRect(x: view.frame.maxX, y: 0, width: 150, height: UIScreen.main.bounds.size.height))
            rightView?.backgroundColor = .green
            rightView?.labCustom.text = "It's Right"
            self.view.addSubview(rightView!)
        }
        
        if indexOfRight % 2 == 1 {
            UIView.animate(withDuration: 0.5, animations: {
                self.rightView?.frame.origin.x -= 150
            }, completion: nil)
        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.rightView?.frame.origin.x += 150
            }, completion: nil)
        }
        
    }
    
    // Bottom 按鈕
    @IBAction func btnShowBootom(_ sender: UIButton) {
        indexOfBottom += 1
        
        if bottomView == nil {
            bottomView = MyView(frame: CGRect(x: 0, y: view.frame.maxY, width: UIScreen.main.bounds.size.width, height: 150))
            bottomView?.backgroundColor = .black
            bottomView?.labCustom.text = "Hi! Bottom View"
            self.view.addSubview(bottomView!)
        }
        
        if indexOfBottom % 2 == 1 {
            UIView.animate(withDuration: 0.5, animations: {
                self.bottomView?.frame.origin.y -= 150
            }, completion: nil)
        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.bottomView?.frame.origin.y += 150
            }, completion: nil)
        }
    }
    
    
}


 檔案下載:
https://github.com/terryyamg/JumpViewTest
 參考連結:
https://stackoverflow.com/documentation/ios/1362/custom-uiviews-from-xib-files#t=201706280220545656796
https://www.youtube.com/watch?v=EBYdsYwoJVI&t=492s
https://www.youtube.com/watch?v=MMgfnrddOxY

2016年5月8日 星期日

iOS Swift GPS 定位

定位功能

1.Main.storyboard拉label

2.在Info.plist的 Information Property List點"+",
在左邊key輸入"NSLocationWhenInUseUsageDescription"
在右邊Value輸入"The application uses this information to show you your location"

3.ViewController.swift

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
    
    
    @IBOutlet weak var lblLat: UILabel!
    @IBOutlet weak var lblLon: UILabel!
    @IBOutlet weak var lblHorizontal: UILabel!
    @IBOutlet weak var lblAltitude: UILabel!
    @IBOutlet weak var lblVertical: UILabel!
    @IBOutlet weak var lblDistance: UILabel!
    
    var locationManager: CLLocationManager = CLLocationManager()
    var startLocation: CLLocation!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        
        startLocation = CLLocation(latitude: 22.6657786, longitude: 120.3033831) //目標緯度經度
        
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        //定位資訊
        let latestLocation: AnyObject = locations[locations.count - 1]
        
        lblLat.text = String(format: "%.4f", latestLocation.coordinate.latitude) //緯度
        lblLon.text = String(format: "%.4f", latestLocation.coordinate.longitude) //經度
        lblHorizontal.text = String(format: "%.4f", latestLocation.horizontalAccuracy) //水平精度
        lblAltitude.text = String(format: "%.4f", latestLocation.altitude) //海拔高度
        lblVertical.text = String(format: "%.4f", latestLocation.verticalAccuracy) //垂直精度
        
        let distanceBetween: CLLocationDistance =
            latestLocation.distanceFromLocation(startLocation) //計算startLocation與latestLocation距離
        
        lblDistance.text = String(format: "%.2f", distanceBetween) //距離 公尺
    }
    
    func locationManager(manager: CLLocationManager,
                         didFailWithError error: NSError) {
        
    }
    
}



3.參考連結:
http://www.techotopia.com/index.php/A_Swift_Example_iOS_8_Location_Application
http://stackoverflow.com/questions/29931302/initialize-a-cllocation-object-in-swift-with-latitude-and-longitude

2016年4月21日 星期四

iOS Swift Photo Gallery Collection View 照片 相簿

iOS Swift的相簿使用
1.建立專案後,拉一個Collection View


2.拉一個Image View進去Collection View Cell裡面

3.點選Collection View Cell -> 在Identifier輸入名稱 這裡設定cell

4.在Collection View點右鍵 ->連結dataSource與delegate到View Controller


5.建立一個Cell.swift檔案,點選cell,在Class選擇Cell
接著把Image View拉過去建立 var imgView

import UIKit

class Cell: UICollectionViewCell {
    

    @IBOutlet var imgView: UIImageView!
    
}







6.放入兩張測試用圖片

7.ViewController.swift
import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate{

    let photoCount = 2 //照片張數
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return photoCount
    }
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        //取得cell
        let cell: Cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! Cell
        print("indexPath:\(indexPath.row)")
        if indexPath.row == 0{
            cell.imgView.image = UIImage(named: "p1.jpg") // 放入第一張
        }else{
            cell.imgView.image = UIImage(named: "p2.jpg") // 放入第二張
        }
        
        return cell
    }

}


檔案下載:
https://github.com/terryyamg/PhotosGalleryTest
參考來源:
https://github.com/TDAbboud/PhotosGalleryApp
http://www.brianjcoleman.com/tutorial-collection-view-using-swift/

2016年4月3日 星期日

iOS Swift Radio Button

1.建立一個專案
2.建立兩個SSRadioButton.swift與SSRadioButtonsController.swift檔案


SSRadioButton.swift
//
//  SSRadioButton.swift
//  SampleProject
//
//  Created by Shamas on 18/05/2015.
//  Copyright (c) 2015 Al Shamas Tufail. All rights reserved.
//

import Foundation
import UIKit
@IBDesignable

class SSRadioButton: UIButton {
    
    private var circleLayer = CAShapeLayer()
    private var fillCircleLayer = CAShapeLayer()
    override var selected: Bool {
        didSet {
            toggleButon()
        }
    }
    /**
     Color of the radio button circle. Default value is UIColor red.
     */
    @IBInspectable var circleColor: UIColor = UIColor.redColor() {
        didSet {
            circleLayer.strokeColor = circleColor.CGColor
            self.toggleButon()
        }
    }
    /**
     Radius of RadioButton circle.
     */
    @IBInspectable var circleRadius: CGFloat = 5.0
    @IBInspectable var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }
    
    private func circleFrame() -> CGRect {
        var circleFrame = CGRect(x: 0, y: 0, width: 2*circleRadius, height: 2*circleRadius)
        circleFrame.origin.x = 0 + circleLayer.lineWidth
        circleFrame.origin.y = bounds.height/2 - circleFrame.height/2
        return circleFrame
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }
    
    private func initialize() {
        circleLayer.frame = bounds
        circleLayer.lineWidth = 2
        circleLayer.fillColor = UIColor.clearColor().CGColor
        circleLayer.strokeColor = circleColor.CGColor
        layer.addSublayer(circleLayer)
        fillCircleLayer.frame = bounds
        fillCircleLayer.lineWidth = 2
        fillCircleLayer.fillColor = UIColor.clearColor().CGColor
        fillCircleLayer.strokeColor = UIColor.clearColor().CGColor
        layer.addSublayer(fillCircleLayer)
        self.titleEdgeInsets = UIEdgeInsetsMake(0, (4*circleRadius + 4*circleLayer.lineWidth), 0, 0)
        self.toggleButon()
    }
    /**
     Toggles selected state of the button.
     */
    func toggleButon() {
        if self.selected {
            fillCircleLayer.fillColor = circleColor.CGColor
        } else {
            fillCircleLayer.fillColor = UIColor.clearColor().CGColor
        }
    }
    
    private func circlePath() -> UIBezierPath {
        return UIBezierPath(ovalInRect: circleFrame())
    }
    
    private func fillCirclePath() -> UIBezierPath {
        return UIBezierPath(ovalInRect: CGRectInset(circleFrame(), 2, 2))
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        circleLayer.frame = bounds
        circleLayer.path = circlePath().CGPath
        fillCircleLayer.frame = bounds
        fillCircleLayer.path = fillCirclePath().CGPath
        self.titleEdgeInsets = UIEdgeInsetsMake(0, (2*circleRadius + 4*circleLayer.lineWidth), 0, 0)
    }
    
    override func prepareForInterfaceBuilder() {
        initialize()
    }
}

SSRadioButtonsController.swift
//
//  RadioButtonsController.swift
//  TestApp
//
//  Created by Al Shamas Tufail on 24/03/2015.
//  Copyright (c) 2015 Al Shamas Tufail. All rights reserved.
//

import Foundation
import UIKit

/// RadioButtonControllerDelegate. Delegate optionally implements didSelectButton that receives selected button.
@objc protocol SSRadioButtonControllerDelegate {
    /**
     This function is called when a button is selected. If 'shouldLetDeSelect' is true, and a button is deselected, this function
     is called with a nil.
     
     */
    optional func didSelectButton(aButton: UIButton?)
}

class SSRadioButtonsController : NSObject
{
    private var buttonsArray = [UIButton]()
    private weak var currentSelectedButton:UIButton? = nil
    weak var delegate : SSRadioButtonControllerDelegate? = nil
    /**
     Set whether a selected radio button can be deselected or not. Default value is false.
     */
    var shouldLetDeSelect = false
    /**
     Variadic parameter init that accepts UIButtons.
     
     - parameter buttons: Buttons that should behave as Radio Buttons
     */
    init(buttons: UIButton...) {
        super.init()
        for aButton in buttons {
            aButton.addTarget(self, action: #selector(SSRadioButtonsController.pressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
        }
        self.buttonsArray = buttons
    }
    /**
     Add a UIButton to Controller
     
     - parameter button: Add the button to controller.
     */
    func addButton(aButton: UIButton) {
        buttonsArray.append(aButton)
        aButton.addTarget(self, action: #selector(SSRadioButtonsController.pressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
    }
    /**
     Remove a UIButton from controller.
     
     - parameter button: Button to be removed from controller.
     */
    func removeButton(aButton: UIButton) {
        let iteration = 0
        var iteratingButton: UIButton? = nil
        for i in iteration..<buttonsArray.count {
            iteratingButton = buttonsArray[i]
            if(iteratingButton == aButton) {
                break
            } else {
                iteratingButton = nil
            }
        }
        if(iteratingButton != nil) {
            buttonsArray.removeAtIndex(iteration)
            iteratingButton!.removeTarget(self, action: #selector(SSRadioButtonsController.pressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
            if currentSelectedButton == iteratingButton {
                currentSelectedButton = nil
            }
        }
    }
    /**
     Set an array of UIButons to behave as controller.
     
     - parameter buttonArray: Array of buttons
     */
    func setButtonsArray(aButtonsArray: [UIButton]) {
        for aButton in aButtonsArray {
            aButton.addTarget(self, action: #selector(SSRadioButtonsController.pressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
        }
        buttonsArray = aButtonsArray
    }
    
    func pressed(sender: UIButton) {
        if(sender.selected) {
            if shouldLetDeSelect {
                sender.selected = false
                currentSelectedButton = nil
            }
        } else {
            for aButton in buttonsArray {
                aButton.selected = false
            }
            sender.selected = true
            currentSelectedButton = sender
        }
        delegate?.didSelectButton?(currentSelectedButton)
    }
    /**
     Get the currently selected button.
     
     - returns: Currenlty selected button.
     */
    func selectedButton() -> UIButton? {
        return currentSelectedButton
    }
}
3.在Main.storyboard拉三個button

4.連結Button至ViewController.swift

5.選擇Buuton->點選Show the Identity inspector ->Class選SSRadioButton
方法一:點選+ 新增circleColor與circleRadius

方法二:點選Show the Attributes inspector會出現Radio Button 去設定

6.ViewController.swift
import UIKit

class ViewController: UIViewController, SSRadioButtonControllerDelegate  {

    @IBOutlet weak var bt1: UIButton!
    @IBOutlet weak var bt2: UIButton!
    @IBOutlet weak var bt3: UIButton!
    
    var radioButtonController: SSRadioButtonsController?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        radioButtonController = SSRadioButtonsController(buttons: bt1, bt2, bt3)
        radioButtonController!.delegate = self
        radioButtonController!.shouldLetDeSelect = true //true:點第二下取消 false:點第二下仍是選擇
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func didSelectButton(aButton: UIButton?) {
        let currentButton = radioButtonController!.selectedButton()!
        print("點選\(currentButton.currentTitle!)")
    }


}





檔案下載: https://github.com/terryyamg/Swift-RadioButtonTest
參考連結: https://github.com/shamasshahid/SSRadioButtonsController

2015年8月5日 星期三

iOS Swift Multiple PickerView Spinner 多重 關聯 連動 滾輪

2017.06.18 update Android的下拉選項為Spinner
相對應的iOS的為滾輪PickerView

1.首先在Main.storyboard拖拉一個Picker View元件
並點選右方Show the Connections inspector
將dataSource與delegate拉致上方圖片上三個小圖的最左邊小圖關聯
2.將storyboard元件拉至ViewController

3.ViewController繼承UIPickerViewDelegate, UIPickerViewDataSource

4.ViewController.swift

//
//  ThreePickerViewController.swift
//  MultiplePickerViewTest
//
//  Created by Terry Yang on 2017/6/18.
//  Copyright © 2017年 terryyamg. All rights reserved.
//

import UIKit

class ThreePickerViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    
    @IBOutlet weak var picker3: UIPickerView!
    
    //第一輪
    var list1  = ["亞洲","歐洲"]
    //第二輪
    var list21 = ["日本","台灣"]
    var list22 = ["英國","德國","義大利"]
    //第三輪
    var list211 = ["東京","沖繩","北海道"]
    var list212 = ["台北","台中","台南","高雄","台東"]
    var list221 = ["倫敦"]
    var list222 = ["柏林"]
    var list223 = ["羅馬"]
    
    //init
    var island : String = "亞洲"
    var country : String = "日本"
    var city : String = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        picker3.delegate = self
        picker3.dataSource = self
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //幾個滾輪
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 3
    }
    
    //確認各個滾輪有幾筆
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        //component - 第幾個滾輪
        switch(component){
        case 0:
            return list1.count
        case 1:
            return island == "亞洲" ? list21.count : list22.count
        case 2:
            switch country {
            case "日本":
                return list211.count
            case "台灣":
                return list212.count
            case "英國":
                return list221.count
            case "德國":
                return list222.count
            case "義大利":
                return list223.count
            default:
                return 0
            }
        default:
            return 0
        }
    }
    
    //放入內容
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch(component){
        case 0:
            return list1[row]
        case 1:
            //true: 回傳第二輪的亞洲內容 false: 回傳第二輪的歐洲內容
            return island == "亞洲" ? list21[row] : list22[row]
        case 2:
            switch country {
            case "日本":
                return list211[row]
            case "台灣":
                return list212[row]
            case "英國":
                return list221[row]
            case "德國":
                return list222[row]
            case "義大利":
                return list223[row]
            default:
                return nil
            }
        default:
            return nil
        }
    }
    
    //回傳選擇的字串
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch component {
        case 0:
            island = list1[row]
            updateCountry(0)
            updateCity(0)
            print("洲: \(island)")
            //選擇第一個滾輪後-重新載入
            pickerView.reloadAllComponents()
            //第二個與第三個滾輪回到第一個項目
            pickerView.selectRow(0, inComponent: 1, animated: true)
            pickerView.selectRow(0, inComponent: 2, animated: true)
        case 1:
            updateCountry(row)
            updateCity(0)
            print("國: \(country)")
            //選擇第二個滾輪後-重新載入
            pickerView.reloadAllComponents()
            //第三個滾輪回到第一個項目
            pickerView.selectRow(0, inComponent: 2, animated: true)

        case 2:
            updateCity(row)
            print("城: \(city)")
        default:
            print("無")
        }
        
    }
    
    func updateCountry(_ row: Int){
        if island == "亞洲" {
            country = list21[row]
        } else {
            country = list22[row]
        }
    }
    
    func updateCity(_ row: Int){
        switch country {
        case "日本":
            city = list211[row]
        case "台灣":
            city = list212[row]
        case "英國":
            city = list221[row]
        case "德國":
            city = list222[row]
        case "義大利":
            city = list223[row]
        default:
            print("無")
        }
        
    }
    
}


檔案下載:
 https://github.com/terryyamg/MultiplePickerViewTest
參考來源:
http://stackoverflow.com/questions/30832489/reload-component-in-ui-picker-view-swift
https://stackoverflow.com/questions/11191062/how-to-reset-uipickerview-to-index0-iphone