仿製LINE密碼解鎖畫面

[iOS App Development]if-else passcode練習

這次練習是模仿LINE密碼解鎖畫面,一直很想使用宮崎駿的素材來做練習,終於給我逮到機會來做一個無臉男主題的解鎖畫面。

◎解鎖規則:

  1. 正確密碼已經事先定義,密碼為四位數字0000。
  2. 使用者每輸入一個數字一個無臉男就會出現,然後輸入完第四個數字就會進行檢查。
  3. 密碼正確顯示正確訊息;密碼錯誤顯示錯誤訊息,並且清空使用者輸入的所有數字回到一開始的狀態。

介面規劃

是不是很像真的解鎖畫面呢!

前置變數與Outlet

先將會經常使用到的變數和IBOutlet做好。

    //設定正確密碼為一個陣列
let password = [0, 0, 0, 0]
//使用者輸入數字也是用一個陣列存起來,一開始目前是空的
var userInputs: [Int] = []
//四個無臉男圖片檔案名稱存入陣列
let facelessMenFileNames = ["facelessMan1.png", "facelessMan2.png", "facelessMan3.png", "facelessMan4.png"]
//建立好用來顯示無臉男圖片的imageViews陣列
var digitImageViews: [UIImageView] = []
//密碼圖像區塊View outlet
@IBOutlet weak var firstDigitView: UIView!

@IBOutlet weak var secondDigitView: UIView!

@IBOutlet weak var thirdDigitView: UIView!

@IBOutlet weak var fourthDigitView: UIView!

//數字0~9和刪除button outlet
@IBOutlet weak var deleteButton: UIButton!

@IBOutlet weak var resultLabel: UILabel!

@IBOutlet weak var oneButton: UIButton!

@IBOutlet weak var twoButton: UIButton!

@IBOutlet weak var threeButton: UIButton!

@IBOutlet weak var fourButton: UIButton!

@IBOutlet weak var fiveButton: UIButton!

@IBOutlet weak var sixButton: UIButton!

@IBOutlet weak var sevenButton: UIButton!

@IBOutlet weak var eightButton: UIButton!

@IBOutlet weak var nineButton: UIButton!

@IBOutlet weak var zeroButton: UIButton!

//四個無臉男圖片imageView outlet
@IBOutlet weak var firstDigitImageView: UIImageView!

@IBOutlet weak var secondDigitImageView: UIImageView!

@IBOutlet weak var thirdDigitImageView: UIImageView!

@IBOutlet weak var fourthDigitImageView: UIImageView!

viewDidLoad說明

一開始的畫面看似簡單但其實有一些工要在viewDidLoad裡面完成,包括:

・將四個密碼圖片區塊用mask做出無臉男的剪影和無臉男的圖片。

//四個密碼圖區塊View
let digitViews = [firstDigitView, secondDigitView, thirdDigitView, fourthDigitView]
//四個imageViews,用來裝無臉男圖片
digitImageViews = [firstDigitImageView, secondDigitImageView, thirdDigitImageView, fourthDigitImageView]
//使用for loop將陣列和一開始宣告好的map起來,依序設定剪影mask和無臉男圖片
for index in 0...digitViews.count - 1 {
let mask = UIImageView(image: UIImage(named: facelessMenFileNames[index]))
digitViews[index]!.mask = mask
digitImageViews[index].frame = CGRect(origin: .zero, size: mask.frame.size)
digitImageViews[index].isHidden = true
}

・將按鈕的數字放大(需要用到AttributedString)。

//將所有數字button先用陣列整理好
let numberButtons = [zeroButton, oneButton, twoButton, threeButton, fourButton, fiveButton, sixButton, sevenButton, eightButton, nineButton]
//使用for loop來套用特定樣式到數字button裡的title
for index in 0...numberButtons.count - 1 {
var title = AttributedString(String(index))
title.font = UIFont(name: "Helvetica", size: 30)
numberButtons[index]?.setAttributedTitle(NSAttributedString(title), for: .normal)
}

・放大刪除按鈕的圖案、隱藏結果訊息label

//在viewDidLoad()之前已經定義
enlargeDeleteButtonImage()
resultLabel.isHidden = true

數字按鈕觸發事件

接著思考按下每個數字會發生什麼事:

  1. 將按下的數字存到userInputs陣列裡。
  2. 每次按下都要檢查userInputs的長度,一旦長度到達4就要檢查是否和真正的密碼相符。
  3. 按下數字後對應密碼位數的無臉男要顯示出來。

因為無論按下哪個數字,都會觸發相同的事件,只有append到陣列裡的數字會不同,所以將所有的數字button都連到同一個IBAction就好,關鍵在於要能夠取出每個button的title,否則就還是要逐個button拉IBAction。

@IBAction func inputNumberButtons(_ sender: UIButton) {
//檢查userInputs如果長度為4就直接結束action,用在解鎖成功的時
if userInputs.count == 4 {
return
}
//輸入數字時要清空之前的結果訊息
resultLabel.text = ""
//從button的attributedTitle擷取按了哪個數字
let userInput = sender.attributedTitle(for: .normal)?.string
//字串轉為整數型態
let userInputInt = Int(userInput!)!
//加到userInputs陣列中
userInputs.append(userInputInt)
//根據輸入了幾個密碼位數來顯示幾個無臉男
showDigitImage()
//加入陣列後再次確認長度,必要時就核對密碼
checkInputsCount()

}

刪除按鈕觸發事件

刪除按鈕按下後會觸發以下動作:

  1. 同樣檢查userInputs,如果長度為0就不動作;不為0時就要刪除最後一個位數。
  2. 根據按下刪除後的userInputs長度來顯示對應數量的無臉男。
@IBAction func deleteOneDigit(_ sender: Any) {
//如果長度為0就代表不用作用,直接return
if userInputs.count == 0 {
return
}
//刪除時也清空結果訊息
resultLabel.text = ""
//彈出userInpus最後一個位數,_代表return出來的東西後續不再使用
let _ = userInputs.popLast()
//處理完之後再檢查一次userInputs,如果為0就隱藏全部無臉男
//如果不為0就先全部隱藏後再顯示對應數量的無臉男
if userInputs.count == 0 {
hideAllDigitImages()
} else {
hideAllDigitImages()
showDigitImage()
}
}

Storyboard的注意點

數字鍵盤不難做,但花了時間研究密碼圖片怎麼顯示比較好,得出結論最單純的就是用.isHidden來控制。而這邊storyboard要特別注意的地方。因為密碼尚未輸入和輸入後使用同張圖片作為剪影和顯示的圖像,所以要將用來顯示圖片的imageViews和整個密碼圖區塊容器view的位置、大小一樣,這樣無臉男顯示出來才能剛好落在剪影上。

相關使用到的函式有興趣的同好可以再參考專案Github,實際操作的畫面如下,第一次和第二次輸入錯誤,第三次輸入正確密碼:

Github:

--

--