这是一个基本的 app 内建键盘。相同的方法可以用来制作任意键盘布局。主要需要完成这些事:
- 在一个 .xib 文件里创建键盘布局,owner 是一个 .swift 文件,包含一个
UIView
子类。 - 告诉
UITextField
使用自定义键盘。 - 使用 delegate 在键盘和主视图控制器之间通信。
创建 .xib 键盘布局文件
- 在 Xcode 里点击 File > New > File... > iOS > User Interface > View 来创建 .xib 文件。
- 我把自己的称为 Keyboard.xib
- 添加你需要的按钮。
- 使用 auto layout constraints,这样不论键盘的大小是多少,按钮都会因此改变大小。
- 设置 File's Owner (不是 root view)为 Keyboard.swift 文件。这里通常会出现错误。最后会讲。
创建 .swift UIView 子类键盘文件
在 Xcode 里点击 File > New > File... > iOS > Source > Cocoa Touch Class 来创建 .swift 文件。
我把自己的成为 Keyboard.swift
-
添加如下代码:
import UIKit // view controller 会采用这个协议(delegate) // 这样它就必须包含 keyWasTapped 方法 protocol KeyboardDelegate: class { func keyWasTapped(character: String) } class Keyboard: UIView { // 这个变量会被设置为 view controller 然后 // 键盘就能给 view controller 发送消息 weak var delegate: KeyboardDelegate? // MARK:- 键盘初始化 required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initializeSubviews() } override init(frame: CGRect) { super.init(frame: frame) initializeSubviews() } func initializeSubviews() { let xibFileName = "Keyboard" // 不包括 xib 后缀名 let view = NSBundle.mainBundle().loadNibNamed(xibFileName, owner: self, options: nil)[0] as! UIView self.addSubview(view) view.frame = self.bounds } // MARK:- .xib 文件里的按钮 action @IBAction func keyTapped(sender: UIButton) { // 按钮被按下后,发送信息给 // delegate (也就是, 那个 view controller) self.delegate?.keyWasTapped(sender.titleLabel!.text!) // 也可以选择发送 tag 值 } }
按住 control 从 .xib 文件里的按钮拖到 .swift 文件里的
@IBAction
方法,这样就能把它们绑定在一起注意协议和 delegate 代码。看这篇答案简单解释了 delegate 是如何工作的。
设置 View Controller
添加一个
UITextField
到 main storyboard 里,然后用一个IBOutlet
连接到你的 view controller。称它为textField
。-
给 View Controller 使用下面的代码:
import UIKitclass ViewController: UIViewController, KeyboardDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() // 初始化自定义键盘 let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300)) keyboardView.delegate = self // 键盘会通知视图控制器,在按下一个键的时候 // 替换系统键盘为自定义键盘 textField.inputView = keyboardView } // 键盘 delegate 协议必须的方法 func keyWasTapped(character: String) { textField.insertText(character) } }
注意 view controller 采用了我们在上面定义的
KeyboardDelegate
协议。
常见错误
如果你得到了一个 EXC_BAD_ACCESS 错误,大概是因为你设置了 view 的 custom class 为 Keyboard.swift 而不是 nib File's Owner。
选择 Keyboard.nib 然后选择 File's Owner。
确定 root view 的 custom class 是空的。