旋轉吧!使用UIPickerView元件與Emoji繪文字打造拉霸機App

在iOS程式中,UIPickerView通過滾輪界面提供單項或多值選項。這篇Swift教學會為你介紹UIPickerView元件,透過打造一個Emoji拉霸機App,你將會透徹瞭解如何使用UIPickerView。


這些年來,由於貼圖的盛行,許多人在聊天的過程中,喜歡用圖形來表達,用得好,有些時候甚至比文字更能傳達心中的意思。而Emoji繪文字也在這一波潮流中水漲船高,更多人注意到它的存在!現在就讓我們利用Emoji繪文字結合UIPickerView元件,自製一個小小拉霸機吧!

emoji-slotmachine

新增一個單一畫面樣板的專案

首先打開Xcode,選擇 Create a new Xcode project。點選 iOS > Application > Single View Application,然後按 Next。

uipickerview-controller-create-project

專案名稱(Product Name)取名為SlotMachine、組織名稱(Organization Name)與Organization Identifier(組織識別)請自行命名、選擇Swift程式語言、Devices裝置為Universal,下面三個選項此範例不會使用到,無需勾選,之後按 Next 繼續。

slotmachine-project-options

佈置UIPickerView元件

專案建立後,請點擊左方Project Navigator區中的Main.storyboard,我們會在畫面上放入UIPickerView、UILabel以及UIButton。

首先,從元件庫選取Picker View並加至View Controller,我們可以讓其與畫面等寬,並且順著狀態列的邊界擺放。放置完成後,放置完成後,按下右下方[Resolve Auto Layout Issues]裡的Add Missing Constraints。

add-uipickerview

之後,加入中間的 SPIN 按鈕,將之置中對齊,並與上方的PickerView有個距離。放置完成後一樣點擊Add Missing Constraints選項加入所需的constraints。

adding-spin-button

最後,在最下方加入Label,與畫面等寬,並與畫面最底下保持一定距離,然後點擊Add Missing Constraints。

adding-label

ViewController.swift中,建立三項畫面與程式的關聯性 (包括兩個IBOutlet及一個IBAction):

@IBOutlet weak var pickerView: UIPickerView!
@IBOutlet weak var resultLabel: UILabel!

@IBAction func buttonClicked(sender: AnyObject) {
}
編者按:你可以利用Assistant Editor建立IBOutlet及IBAction。只要按住滑鼠左鍵從Storyboard 選取所需聯繫的元件(例如PickerView)並拖曳至ViewController.swift(見下圖),鬆開按鈕之後,你就可以建立相關的outlet或action。

adding-outlets

建立需要的資料儲存變數及加上要遵循的協定

現在是時候建立需要的資料儲存變數。另外,加上要遵循的UIPickerViewDelegate及UIPickerViewDataSource協定。我們會建立四個陣列變數,包括:

  • imageArray – 存放繪文字以供三個滾軸使用
  • dataArray1 – 第一個滾軸對應要顯示的資料來源陣列
  • dataArray2 – 第二個滾軸對應要顯示的資料來源陣列
  • dataArray3 – 第三個滾軸對應要顯示的資料來源陣列

ViewController.swift中,加上要遵循的協定UIPickerViewDelegate並宣告宣告所需的陣列變數:

class ViewController: UIViewController, UIPickerViewDelegate {

    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var resultLabel: UILabel!
    
    var imageArray = [String]()
    var dataArray1 = [Int]()
    var dataArray2 = [Int]()
    var dataArray3 = [Int]()
    
    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.
    }

    @IBAction func buttonClicked(sender: AnyObject) {
    }
}

輸入資料並且設定委任對象

之前,我們在宣告陣列時初始陣列預設為空的。在viewDidLoad方法,我們會輸入資料並且設定pickerView的委任對象。另外,將resultLabel設定為空白。

override func viewDidLoad() {
    super.viewDidLoad()
    
    imageArray = ["🍎","😍","🐮","🐼","🐔","🎅","🚍","💖","👑","👻"]
    
    for(var i = 0; i < 100; i++) {
        dataArray1.append((Int)(arc4random() % 10))
        dataArray2.append((Int)(arc4random() % 10))
        dataArray3.append((Int)(arc4random() % 10))
    }
    
    resultLabel.text = ""

    pickerView.delegate = self
    pickerView.dataSource = self
}

我們透過這三個陣列來對應儲存每個滾軸要顯示的繪文字,所以以亂數的方式來產生這些資料。

小技巧:如何輸入繪文字(Emoji)?按下 Ctrl + Command + 空白鍵 就可以了。

採用UIPickViewDataSource及UIPickViewDelegate協定

接下來我們將採用幾個UIPickViewDataSource協定的方法並提供幾個PickerView相關數字。首先,加入以下面的程式:

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return 100
}

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    return 3
}

第一個方法決定PickerView的每一個滾軸(Component)有幾個列(Row),回傳數字設定為100。回傳數字多少取決於之前的陣列變數是多少(即是 100),在這個範例裡為了製造拉霸機的滾動感覺,故此數字亦設定大一些。

第二個方法決定整個PickerView要有幾個滾軸(Component)。

之後再加入以下方法以實現UIPickViewDelegate協定。

func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
    return 100.0
}

func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat{
    return 100.0
}

以上兩個方法決定PickerView上每一個滾軸的寬度及高度。

uipickerview-row-column

最後加入以下方法來設定Emoji繪文字並顯示於PickerView上:

func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
    
    let pickerLabel = UILabel()
    
    if component == 0 {
        pickerLabel.text = imageArray[(Int)(dataArray1[row])]
    } else if component == 1 {
        pickerLabel.text = imageArray[(Int)(dataArray2[row])]
    } else {
        pickerLabel.text = imageArray[(Int)(dataArray3[row])]
    }
    
    pickerLabel.font = UIFont(name: "Arial-BoldMT", size: 80)
    pickerLabel.textAlignment = NSTextAlignment.Center

    return pickerLabel
}

要將繪文字顯示於PickerView上,我們可以透過實現pickerView(_:viewForRow:forComponent:reusingView:),回傳自定的視圖。

首先,我們建立一個UILabel物件,命名為pickerLabel。第0號component(即最左邊的滾軸)對應dataArray1,轉到第X列就去陣列裡面取出第X個資料,依此類推至第1號component與第2號component。最後在設定pickerLabel的字型、大小以及對齊方式。

Spin 按鈕 - 旋轉吧!

當使用者按下按鈕時,轉動滾軸,若三個圖案相同,顯示Bingo。之前,我們已建立了buttonClicked這個IBAction方法,是時候加入所須的程式:

@IBAction func buttonClicked(sender: AnyObject) {
    pickerView.selectRow(Int(arc4random())%94 + 3, inComponent: 0, animated: true)
    pickerView.selectRow(Int(arc4random())%94 + 3, inComponent: 1, animated: true)
    pickerView.selectRow(Int(arc4random())%94 + 3, inComponent: 2, animated: true)

    if(dataArray1[pickerView.selectedRowInComponent(0)] == dataArray2[pickerView.selectedRowInComponent(1)] &&
        dataArray2[pickerView.selectedRowInComponent(1)] == dataArray3[pickerView.selectedRowInComponent(2)]) {

        resultLabel.text = "Bingo!!";
    } else {
        resultLabel.text = ""
    }
}

你可以利用selectRow方法跳至特定列,arc4random( ) 產生亂數,為避免轉到太邊邊,所以我們把數字控制在3 ~ 96。最後,當目前所選的三個列所對應的陣列位置中的數字是相同的時候,就代表取出的圖案也會是相同的,顯示使用者Bingo!

試試看,你是不是也完成了自己的拉霸機呢?

emoji-slotmachine

為了讓你進一步參考,你可以 在這裏下載Xcode專案。對於這篇教學你有什麼意見呢?請留言給我並分享你的想法。


行動開發學院創辦人,現職為資策會課程研發經理,擔任「行動開發」課程總監,專長於iOS APP開發、HTML5 Web開發,並於中央大學資管系、元智大學資工系等多所學校授課,致力推廣APP開發教育。與我聯繫:[email protected]。網站:www.mobiledev.tw

blog comments powered by Disqus
Shares
Share This