如何创建自定义iOS键盘。

5
首先,我要让您知道,我已经查阅了许多StackOverflow、Google和Github上的帖子。我已经搜遍了所有地方,寻找任何可以帮助我的东西。但是,似乎没有什么东西有效。或者它已经过时(10年以上),或者完全用Objective-C编写。我知道有关此主题的其他帖子,但我需要在Swift 5.0+中找到一个解决方案,而不是11年前在Obj-C中完全过时的古老方案。
现在,我的问题是:我需要为我的iOS应用程序开发一个键盘。它需要是一个数字/操作器类型的键盘,实际上是一个基本的数学键盘。
我不知道从哪里开始,我对Swift/iOS开发总体上还很陌生。
我尝试使用KeyboardKit (请参见Github页面), 但没有成功;文档非常简单,对于初学者来说根本不足以有效地使用。
我尝试了许多不同的GitHub库,但没有一个符合我的需求。
总之,我的键盘需要设置为应用程序的默认键盘(但我会在另一个问题中询问这个);因此,它需要该选项。它需要完全(易于=)可定制。并且它需要像默认的苹果键盘一样运作。
我正在寻找相关且可扩展的东西。
干杯!
1个回答

2
我已经解决了我的问题。我在StackOverflow上发现了这个网站,完全解决了我的问题。我能够将自定义键添加到键盘中,这是我的主要问题。
我创建了一个名为DigitButton.swift的类。
import UIKit

class DigitButton: UIButton {
    var digit: Int = 0
}

class NumericKeyboard: UIView {
    weak var target: (UIKeyInput & UITextInput)?
    var useDecimalSeparator: Bool
    
    lazy var parenthesis1: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "("
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapParenthesis1(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var squareroot: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "√"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapSquareRoot(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var parenthesis2: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = ")"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapParenthesis2), for: .touchUpInside)
        return button
    }()
    
    lazy var exponentButton: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "^0"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapExponentButton(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var exponentButton2: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "^2"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapExponentButton2(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var exponentButton3: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "^3"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapExponentButton3(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var exponentButton4: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "^"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapExponentButton4(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var addButton: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "+"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapAddButton(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var subtractButton: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "-"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapSubtractButton(_:)), for: .touchUpInside)
        return button
    }()
    
    lazy var divideButton: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "/"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapDivideButton(_:)), for: .touchUpInside)
        return button
    }()
    
    
    lazy var multiplyButton: UIButton = {
        let button = UIButton(type: .system)
        let decimalSeparator = "*"
        button.setTitle(decimalSeparator, for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.accessibilityLabel = decimalSeparator
        button.addTarget(self, action: #selector(didTapMultiplyButton(_:)), for: .touchUpInside)
        return button
    }()
    
    

    lazy var numericButtons: [DigitButton] = (0...9).map {
        let button = DigitButton(type: .system)
        button.digit = $0
        button.setTitle("\($0)", for: .normal)
        button.titleLabel?.font = .preferredFont(forTextStyle: .title1)
        button.setTitleColor(.black, for: .normal)
        button.layer.borderWidth = 0.5
        button.sizeToFit()
        button.titleLabel?.numberOfLines = 1
        button.titleLabel?.adjustsFontSizeToFitWidth = true
        button.titleLabel?.lineBreakMode = .byTruncatingTail
        button.layer.borderColor = UIColor.darkGray.cgColor
        button.accessibilityTraits = [.keyboardKey]
        button.addTarget(self, action: #selector(didTapDigitButton(_:)), for: .touchUpInside)
        button.inputView.self?.sizeToFit()
        return button
    }

    var deleteButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("⌫", for: .normal)
        button.titleLabel?.font = .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 & UITextInput, useDecimalSeparator: Bool = false) {
        self.target = target
        self.useDecimalSeparator = useDecimalSeparator
        super.init(frame: .zero)
        configure()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: - Actions

extension NumericKeyboard {
    
    @objc func didTapSquareRoot(_ sender: DigitButton) {
        insertText("√")
    }
    
    @objc func didTapParenthesis1(_ sender: DigitButton) {
        insertText("(")
    }
    
    @objc func didTapParenthesis2(_ sender: DigitButton) {
        insertText(")")
    }
    @objc func didTapDigitButton(_ sender: DigitButton) {
        insertText("\(sender.digit)")
    }

    @objc func didTapDecimalButton(_ sender: DigitButton) {
        insertText(Locale.current.decimalSeparator ?? ".")
    }
    
    @objc func didTapExponentButton(_ sender: DigitButton){
        insertText("^0")
    }
    
    @objc func didTapExponentButton2(_ sender: DigitButton){
        insertText("^2")
    }
    
    @objc func didTapExponentButton3(_ sender: DigitButton){
        insertText("^3")
    }
    
    @objc func didTapExponentButton4(_ sender: DigitButton){
        insertText("^")
    }
    
    
    @objc func didTapAddButton(_ sender: DigitButton){
        insertText("+")
    }
    
    
    @objc func didTapSubtractButton(_ sender: DigitButton){
        insertText("-")
    }
    
    
    @objc func didTapDivideButton(_ sender: DigitButton){
        insertText("/")
    }
    
    
    @objc func didTapMultiplyButton(_ sender: DigitButton){
        insertText("*")
    }

    @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)

        subStackView.addArrangedSubview(numericButtons[0])
        
        subStackView.addArrangedSubview(parenthesis1)
        subStackView.addArrangedSubview(parenthesis2)
        subStackView.addArrangedSubview(squareroot)
                
        subStackView.addArrangedSubview(addButton)
        subStackView.addArrangedSubview(subtractButton)
        subStackView.addArrangedSubview(multiplyButton)
        subStackView.addArrangedSubview(divideButton)
        
        
        subStackView.addArrangedSubview(exponentButton)
        subStackView.addArrangedSubview(exponentButton2)
        subStackView.addArrangedSubview(exponentButton4)
        
        subStackView.addArrangedSubview(deleteButton)
        
    }

    func createStackView(axis: NSLayoutConstraint.Axis) -> UIStackView {
        let stackView = UIStackView()
        stackView.axis = axis
        stackView.alignment = .fill
        stackView.distribution = .fillProportionally
        return stackView
    }

    func insertText(_ string: String) {
        guard let range = target?.selectedRange else { return }

        if let textField = target as? UITextField, textField.delegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) == false {
            return
        }

        if let textView = target as? UITextView, textView.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: string) == false {
            return
        }

        target?.insertText(string)
    }
}

// MARK: - UITextInput extension

extension UITextInput {
    var selectedRange: NSRange? {
        guard let textRange = selectedTextRange else { return nil }

        let location = offset(from: beginningOfDocument, to: textRange.start)
        let length = offset(from: textRange.start, to: textRange.end)
        return NSRange(location: location, length: length)
    }
}

然后我使用textField.inputView = NumericKeyboard(target: textField)设置了我的InputView输入法。

这个方法完美地起作用了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接