Sur*_*gch 38 keyboard ios swift custom-keyboard
我想制作一个仅在我的应用程序中使用的自定义键盘,而不是需要安装的系统键盘.
文档
上面的第一篇文章指出:
确保自定义的系统范围键盘确实是您想要开发的.为了仅为您的应用提供完全自定义的键盘,或仅在您的应用中使用自定义键补充系统键盘,iOS SDK提供了其他更好的选择.在iOS文本编程指南的"数据输入自定义视图"中阅读有关自定义输入视图和输入附件视图的信息.
这就是我上面第二篇文章的原因.但是,那篇文章没有足够的细节让我开始.
教程
我能够从上面列表中的第二个教程中获得一个工作键盘.但是,我找不到任何教程,这些教程展示了如何制作一个仅限应用程序的键盘,如数据输入自定义视图文档中所述.
堆栈溢出
在回答当前问题的路上,我也问了(并回答了)这些问题.
有没有人在应用程序自定义键盘中有一个最小的例子(甚至一个按钮)?我不是在寻找一个完整的教程,只是一个概念证明,我可以扩展自己.
Sur*_*gch 70
这是一个基本的应用内键盘.可以使用相同的方法来制作任何键盘布局.以下是需要完成的主要工作:
UIView子类的.swift文件.UITextField使用自定义键盘.添加以下代码:
import UIKit
// The view controller will adopt this protocol (delegate)
// and thus must contain the keyWasTapped method
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
}
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 initialization
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 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
}
}
Run Code Online (Sandbox Code Playgroud)控制从@IBAction.xib文件中的按钮拖动到.swift文件中的方法以将它们全部挂起.
UITextField到主故事板并使用.将其连接到视图控制器IBOutlet.叫它textField.对View Controller使用以下代码:
import UIKit
class ViewController: UIViewController, KeyboardDelegate {
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// initialize custom keyboard
let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
textField.inputView = keyboardView
}
// required method for keyboard delegate protocol
func keyWasTapped(character: String) {
textField.insertText(character)
}
}
Run Code Online (Sandbox Code Playgroud)请注意,视图控制器采用KeyboardDelegate我们在上面定义的协议.
如果您收到EXC_BAD_ACCESS错误,可能是因为您将视图的自定义类设置为Keyboard.swift而不是为nib文件的所有者执行此操作.
选择Keyboard.nib,然后选择File's Owner.
确保根视图的自定义类为空.
在Suragch的回答的基础上,我需要一个完成和退格按钮,如果你是一个像我这样的菜鸟,你可能会遇到一些错误以及我解决它们的方式.
出现EXC_BAD_ACCESS错误? 包括我:
@objc(classname)
class classname: UIView{
}
Run Code Online (Sandbox Code Playgroud)
修复了我的问题但Suragch的更新答案似乎解决了这个更合适/更正确的方法.
得到SIGABRT错误? 另一个愚蠢的事情是以错误的方式拖动连接,导致SIGABRT错误.不要将功能拖动到按钮,而是将按钮拖动到该功能.
添加完成按钮 我将此添加到keyboard.swift中的协议:
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
func keyDone()
}
Run Code Online (Sandbox Code Playgroud)
然后将一个新的IBAction从我的完成按钮连接到keyboard.swift,如下所示:
@IBAction func Done(sender: UIButton) {
self.delegate?.keyDone()
}
Run Code Online (Sandbox Code Playgroud)
然后跳回我的viewController.swift,在那里我使用这个键盘并在函数keyWasTapped之后添加以下内容:
func keyDone() {
view.endEditing(true)
}
Run Code Online (Sandbox Code Playgroud)
添加Backspace 这让我感到很沮丧,因为你必须在viewDidLoad()方法中将textField.delegate设置为self(稍后显示).
第一:在keyboard.swift中添加协议func backspace():
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
func keyDone()
func backspace()
}
Run Code Online (Sandbox Code Playgroud)
第二:连接类似于完成动作的新IBAction:
@IBAction func backspace(sender: UIButton) {
self.delegate?.backspace()
}
Run Code Online (Sandbox Code Playgroud)
第三:到了出现NumberPad的viewController.swift.
重要说明:在viewDidLoad()中设置将使用此键盘的所有textFields.所以你的viewDidLoad()应该是这样的:
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField1.delegate = self
self.myTextField2.delegate = self
// initialize custom keyboard
let keyboardView = keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 240))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
myTextField1.inputView = keyboardView
myTextField2.inputView = keyboardView
}
Run Code Online (Sandbox Code Playgroud)
如果有办法对视图中的所有textField执行此操作,我不确定如何操作.这会很方便......
Forth:仍然在viewController.swift中我们需要添加一个变量和两个函数.它看起来像这样:
var activeTextField = UITextField()
func textFieldDidBeginEditing(textField: UITextField) {
print("Setting Active Textfield")
self.activeTextField = textField
print("Active textField Set!")
}
func backspace() {
print("backspaced!")
activeTextField.deleteBackward()
}
Run Code Online (Sandbox Code Playgroud)
解释这里发生的事情:
你应该做生意.非常感谢Suragchs帮助我实现这一目标.
关键是使用已经符合的现有UIKeyInput协议UITextField。那么你的键盘视图只需要发送insertText(),并deleteBackward()在控制。
下面的示例创建一个自定义数字键盘:
class DigitButton: UIButton {
var digit: Int = 0
}
class NumericKeyboard: UIView {
weak var target: UIKeyInput?
var numericButtons: [DigitButton] = (0...9).map {
let button = DigitButton(type: .system)
button.digit = $0
button.setTitle("\($0)", for: .normal)
button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .largeTitle)
button.setTitleColor(.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.darkGray.cgColor
button.accessibilityTraits = [.keyboardKey]
button.addTarget(self, action: #selector(didTapDigitButton(_:)), for: .touchUpInside)
return button
}
var deleteButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("?", for: .normal)
button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .largeTitle)
button.setTitleColor(.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.darkGray.cgColor
button.accessibilityTraits = [.keyboardKey]
button.accessibilityLabel = "Delete"
button.addTarget(self, action: #selector(didTapDeleteButton(_:)), for: .touchUpInside)
return button
}()
init(target: UIKeyInput) {
self.target = target
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - Actions
extension NumericKeyboard {
@objc func didTapDigitButton(_ sender: DigitButton) {
target?.insertText("\(sender.digit)")
}
@objc func didTapDeleteButton(_ sender: DigitButton) {
target?.deleteBackward()
}
}
// MARK: - Private initial configuration methods
private extension NumericKeyboard {
func configure() {
autoresizingMask = [.flexibleWidth, .flexibleHeight]
addButtons()
}
func addButtons() {
let stackView = createStackView(axis: .vertical)
stackView.frame = bounds
stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(stackView)
for row in 0 ..< 3 {
let subStackView = createStackView(axis: .horizontal)
stackView.addArrangedSubview(subStackView)
for column in 0 ..< 3 {
subStackView.addArrangedSubview(numericButtons[row * 3 + column + 1])
}
}
let subStackView = createStackView(axis: .horizontal)
stackView.addArrangedSubview(subStackView)
let blank = UIView()
blank.layer.borderWidth = 0.5
blank.layer.borderColor = UIColor.darkGray.cgColor
subStackView.addArrangedSubview(blank)
subStackView.addArrangedSubview(numericButtons[0])
subStackView.addArrangedSubview(deleteButton)
}
func createStackView(axis: NSLayoutConstraint.Axis) -> UIStackView {
let stackView = UIStackView()
stackView.axis = axis
stackView.alignment = .fill
stackView.distribution = .fillEqually
return stackView
}
}
Run Code Online (Sandbox Code Playgroud)
那么你也能:
textField.inputView = NumericKeyboard(target: textField)
Run Code Online (Sandbox Code Playgroud)
产生:
上面的内容很原始,但是它说明了这个想法:让您拥有输入视图并使用该UIKeyInput协议将键盘输入传达给控件。
另外,请注意使用accessibilityTraits来获得正确的“语音内容”»“语音屏幕”行为。并且如果您将图像用作按钮,请确保也设置accessibilityLabel了。
| 归档时间: |
|
| 查看次数: |
21811 次 |
| 最近记录: |