(Swift) Create a custom keyboard in your App 在你的 APP 中自定義鍵盤

YEN HUNG CHENG
彼得潘的 Swift iOS App 開發教室
15 min readMay 10, 2022

--

目的:學習如何在 APP 中建立 自定義鍵盤

這邊不會特別說明 delegate,如果不熟悉 delegate 可以參考以下文章

第一步

點選 File > New > File… > iOS > User Interface > View 以創建 .xib 文件

並將其命名為 Keyboard

接下來點選 Size > 選擇 FreeForm > 隨意調整一下高度

第二步

依你的喜好來設計鍵盤,記得要使用 Auto Layout,這樣不管在哪一個裝置都能適配

先新增一個 Button,並設定好背景和文字大小,再來進行複製

選取第一排的四個 button 用 Stack View 將其包住

接下來複製Stack View ,全選全部 Stack View,再用一個 Stack View 包住

簡單設定一下 Auto Layout,選取 View 與 Stack View,新增 Auto Layout

點選所有的 Stack View 設定,並設定好鍵盤文字

Distribution > Fill Equally

Spacing > 0

第三步

點選 File > New > File… > iOS > Source > Cocoa Touch Class >

新增 UIView 子類文件,命名為 Keyboard

在你的 Keyboard.swift 內,新增以下程式

import UIKitprotocol KeyboardDelegate: AnyObject {

// 輸入 按鈕數字
func keyWasTapped(character: String)
// 刪除 數字
func deletTapped()
// 刪除 全部數字
func deletAllTapped()
// 相加 按鍵
func plusTapped()
// 相乘 按鍵
func multiplicationTapped()
// 相減 按鍵
func deductTapped()
// 相除 按鍵
func divisionTapped()
// 計算 按鍵
func calculateTapped()

}
class Keyboard: UIView {// This variable will be set as the view controller so that
// the keyboard can send messages to the view controller.
weak var delegate: KeyboardDelegate?
// MARK:- keyboard initializationrequired init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeSubviews()
}
func initializeSubviews() {
let xibFileName = "Keyboard" // xib extention not included

let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView

self.addSubview(view)
view.frame = self.bounds
}
// MARK:- Button actions from .xib file
// 輸入按鈕 事件
@IBAction func keyTapped(sender: UIButton) {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(character: sender.titleLabel!.text!) // could alternatively send a tag value
}

// delet 事件
@IBAction func keyDelet(sender: UIButton) {
self.delegate?.deletTapped() // could alternatively send a tag value
}

// deletAll 事件
@IBAction func keyDeletAll(sender: UIButton) {
self.delegate?.deletAllTapped() // could alternatively send a tag value
}

// plus 事件
@IBAction func keyplus(sender: UIButton) {
self.delegate?.plusTapped() // could alternatively send a tag value
}

// multiplication 事件
@IBAction func keymultiplication(sender: UIButton) {
self.delegate?.multiplicationTapped() // could alternatively send a tag value
}

// deduct 事件
@IBAction func keydeduct(sender: UIButton) {
self.delegate?.deductTapped() // could alternatively send a tag value
}

// division 事件
@IBAction func keydivision(sender: UIButton) {
self.delegate?.divisionTapped() // could alternatively send a tag value
}

// calculate 事件
@IBAction func keycalculate(sender: UIButton) {
self.delegate?.calculateTapped() // could alternatively send a tag value
}

}

第四步

回到 keyboard.xib 拉 @IBAction

每個鍵盤就對應的一個事件,比數字就是對應到 keyTapped()

剩下的鍵盤以此類推

@IBAction func keyTapped(sender: UIButton) {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(character: sender.titleLabel!.text!) // could alternatively send a tag value
}

第五步

新增一個 TextField 在你的主頁上,並拉 @IBOutlet

在 ViewController 中新增以下變數

var number1 = 0.0
var number2 = 0.0
var calculatetype = ""

接下來讓 ViewController 繼承 KeyboardDelegate

點選 fix 讓 Xcode 把 KeyboardDelegate 的 func 寫出來

extension ViewController: KeyboardDelegate {
func keyWasTapped(character: String) {
<#code#>
}

func deletTapped() {
<#code#>
}

func deletAllTapped() {
<#code#>
}

func plusTapped() {
<#code#>
}

func multiplicationTapped() {
<#code#>
}

func deductTapped() {
<#code#>
}

func divisionTapped() {
<#code#>
}

func calculateTapped() {
<#code#>
}


}

並在 override func viewDidLoad() 中新增以下程式

        // custom keyboard
let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: (view.frame.height) * 4/ 6))
keyboardView.delegate = self
textfield.inputView = keyboardView

第六步

extension ViewController: KeyboardDelegate 中新增以下程式

extension ViewController: KeyboardDelegate {
func keyWasTapped(character: String) {
textfield.insertText(character)
}

func deletTapped() {
textfield.deleteBackward()
} func deletAllTapped() {
textfield.text?.removeAll()
}

func plusTapped() {

if let number = textfield.text ,
number1 == 0 {

number1 = Double(number) ?? 0
textfield.text?.removeAll()
}
calculatetype = "+"


}

func multiplicationTapped() {
if let number = textfield.text ,
number1 == 0 {
number1 = Double(number) ?? 0
textfield.text?.removeAll()
}
calculatetype = "X"

}

func deductTapped() {
if let number = textfield.text ,
number1 == 0 {
number1 = Double(number) ?? 0
textfield.text?.removeAll()
}
calculatetype = "-"

}

func divisionTapped() {
if let number = textfield.text ,
number1 == 0.0 {
number1 = Double(number) ?? 0
textfield.text?.removeAll()
}
calculatetype = "/"

}

func calculateTapped() {
if let number = textfield.text {
number2 = Double(number) ?? 0
switch calculatetype{
case "+":
textfield.text = String(number1 + number2)
case "X":
textfield.text = String(number1 * number2)
case "-":
textfield.text = String(number1 - number2)
case "/":
textfield.text = String(number1 / number2)
default :
print("")
}
number1 = 0.0
number2 = 0.0
}
}

簡單說明一下計算程式

當輸入第一個數字,並在我按下按鈕後,能將數字儲存在 number1 中

為了避免連續按下兩次 + 鍵,造成變數清除,必須加入判斷式

if number1 == 0

也就是下面的位置

    func plusTapped() {
// 若 number1 為 0 ,新增變數
if let number = textfield.text ,
number1 == 0 {

number1 = Double(number) ?? 0
textfield.text?.removeAll()
}
calculatetype = "+"
}

按完我們要計算的方式後,輸入第二個數字

並利用 switch 來看 calculatetype 目前的字串,來判定要進行的運算

       func calculateTapped() {
if let number = textfield.text {
number2 = Double(number) ?? 0
switch calculatetype{
case "+":
textfield.text = String(number1 + number2)
case "X":
textfield.text = String(number1 * number2)
case "-":
textfield.text = String(number1 - number2)
case "/":
textfield.text = String(number1 / number2)
default :
print("")
}
number1 = 0.0
number2 = 0.0
}
}

完成以上步驟後,來看一下成果吧

好像還缺少了什麼?

那就是按下數字的鍵盤反饋

定義鍵盤點選反饋

點選 File > New > File… > iOS > Source > Cocoa Touch Class >

新增 UIButton 子類文件,命名為 CustomButton

在 CustomButton 中,新增以下程式

黑色粗體的那段為點選不放時,所產生的顏色,另一段為鍵盤原本的顏色

class CustomButton: UIButton {

override open var isHighlighted: Bool {
didSet {
backgroundColor = isHighlighted ? UIColor(red: 128/255, green: 183/255, blue: 185/255, alpha: 1) : UIColor(red: 70/255, green: 183/255, blue: 185/255, alpha: 1)
}
}
}

最後到 Keyboard.xib 全選,並將每個按鈕都繼承 CustomButton 即可完成

最近正在做記帳 APP ,所以想要設計鍵盤,讓大家能夠更好操作,查了蠻多的文章,也嘗試了不少的方法,我認為這是我找到所有方法中,最簡單的方法,非常推薦給各位參考,有任何問題歡迎留言與我討論謝謝

GitHub

參考文章

--

--