如何创建自定义 iOS 键盘

Ars*_*cis 6 keyboard ios swift

首先,我想让你知道,我在 StackOverflow 以及 Google 和 Github 上查看了许多不同的帖子。我到处寻找任何对我有帮助的东西。但是,似乎没有任何作用。它要么已经过时(超过 10 年),要么完全用 Objective-C 编写。我知道还有其他关于这个主题的帖子,但我需要 Swift 5.0 + 中的解决方案,而不是 11 年前 Obj-C 中的古老解决方案,如今在所有内容中都已完全弃用。

现在,我的问题。我需要为我的 iOS 应用程序开发一个键盘。它需要是数字/运算符类型的键盘,实际上是基本的数学键盘。

我不知道如何或从哪里开始,总的来说,我对 Swift/iOS 开发还比较陌生。

我尝试过使用 KeyboardKit (参见 Github 页面) , 但没有成功;文档非常,不足以让初学者有效地掌握和使用。

更新 11.13.23:KeyboardKit 的文档得到了极大的改进。我建议您检查一下,看看它是否适合您的需求。

我尝试了许多不同的 GitHub 存储库,但没有一个符合我的需要。

总之,我的键盘需要设置为应用程序的默认键盘(但我稍后会问一个不同的问题);所以它需要这个选项。它需要完全且易于定制。它的行为需要与默认的 Apple 键盘非常相似。

我正在寻找相关且可扩展的东西

干杯!

Ars*_*cis 3

我已经解决了我的问题。我发现了这个网站

\n

StackOverflow 完全解决了我的问题。我能够向键盘添加自定义按键,这是我的主要问题。

\n

我创建了一个名为 DigitButton.swift 的类。

\n
import UIKit\n\nclass DigitButton: UIButton {\n    var digit: Int = 0\n}\n\nclass NumericKeyboard: UIView {\n    weak var target: (UIKeyInput & UITextInput)?\n    var useDecimalSeparator: Bool\n    \n    lazy var parenthesis1: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "("\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapParenthesis1(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var squareroot: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "\xe2\x88\x9a"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapSquareRoot(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var parenthesis2: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = ")"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapParenthesis2), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var exponentButton: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "^0"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapExponentButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var exponentButton2: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "^2"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapExponentButton2(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var exponentButton3: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "^3"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapExponentButton3(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var exponentButton4: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "^"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapExponentButton4(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var addButton: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "+"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapAddButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var subtractButton: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "-"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapSubtractButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    lazy var divideButton: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "/"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapDivideButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    \n    lazy var multiplyButton: UIButton = {\n        let button = UIButton(type: .system)\n        let decimalSeparator = "*"\n        button.setTitle(decimalSeparator, for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = decimalSeparator\n        button.addTarget(self, action: #selector(didTapMultiplyButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    \n\n    lazy var numericButtons: [DigitButton] = (0...9).map {\n        let button = DigitButton(type: .system)\n        button.digit = $0\n        button.setTitle("\\($0)", for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .title1)\n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.sizeToFit()\n        button.titleLabel?.numberOfLines = 1\n        button.titleLabel?.adjustsFontSizeToFitWidth = true\n        button.titleLabel?.lineBreakMode = .byTruncatingTail\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.addTarget(self, action: #selector(didTapDigitButton(_:)), for: .touchUpInside)\n        button.inputView.self?.sizeToFit()\n        return button\n    }\n\n    var deleteButton: UIButton = {\n        let button = UIButton(type: .system)\n        button.setTitle("\xe2\x8c\xab", for: .normal)\n        button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)\n        \n        button.setTitleColor(.black, for: .normal)\n        button.layer.borderWidth = 0.5\n        button.layer.borderColor = UIColor.darkGray.cgColor\n        button.accessibilityTraits = [.keyboardKey]\n        button.accessibilityLabel = "Delete"\n        button.addTarget(self, action: #selector(didTapDeleteButton(_:)), for: .touchUpInside)\n        return button\n    }()\n    \n    \n\n    init(target: UIKeyInput & UITextInput, useDecimalSeparator: Bool = false) {\n        self.target = target\n        self.useDecimalSeparator = useDecimalSeparator\n        super.init(frame: .zero)\n        configure()\n    }\n\n    required init?(coder: NSCoder) {\n        fatalError("init(coder:) has not been implemented")\n    }\n}\n\n// MARK: - Actions\n\nextension NumericKeyboard {\n    \n    @objc func didTapSquareRoot(_ sender: DigitButton) {\n        insertText("\xe2\x88\x9a")\n    }\n    \n    @objc func didTapParenthesis1(_ sender: DigitButton) {\n        insertText("(")\n    }\n    \n    @objc func didTapParenthesis2(_ sender: DigitButton) {\n        insertText(")")\n    }\n    @objc func didTapDigitButton(_ sender: DigitButton) {\n        insertText("\\(sender.digit)")\n    }\n\n    @objc func didTapDecimalButton(_ sender: DigitButton) {\n        insertText(Locale.current.decimalSeparator ?? ".")\n    }\n    \n    @objc func didTapExponentButton(_ sender: DigitButton){\n        insertText("^0")\n    }\n    \n    @objc func didTapExponentButton2(_ sender: DigitButton){\n        insertText("^2")\n    }\n    \n    @objc func didTapExponentButton3(_ sender: DigitButton){\n        insertText("^3")\n    }\n    \n    @objc func didTapExponentButton4(_ sender: DigitButton){\n        insertText("^")\n    }\n    \n    \n    @objc func didTapAddButton(_ sender: DigitButton){\n        insertText("+")\n    }\n    \n    \n    @objc func didTapSubtractButton(_ sender: DigitButton){\n        insertText("-")\n    }\n    \n    \n    @objc func didTapDivideButton(_ sender: DigitButton){\n        insertText("/")\n    }\n    \n    \n    @objc func didTapMultiplyButton(_ sender: DigitButton){\n        insertText("*")\n    }\n\n    @objc func didTapDeleteButton(_ sender: DigitButton) {\n        target?.deleteBackward()\n    }\n}\n\n// MARK: - Private initial configuration methods\n\nprivate extension NumericKeyboard {\n    func configure() {\n        autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        addButtons()\n    }\n\n    func addButtons() {\n        let stackView = createStackView(axis: .vertical)\n        stackView.frame = bounds\n        stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        addSubview(stackView)\n\n        for row in 0 ..< 3 {\n            let subStackView = createStackView(axis: .horizontal)\n            stackView.addArrangedSubview(subStackView)\n\n            for column in 0 ..< 3 {\n                subStackView.addArrangedSubview(numericButtons[row * 3 + column + 1])\n            }\n        }\n\n        let subStackView = createStackView(axis: .horizontal)\n        stackView.addArrangedSubview(subStackView)\n\n        subStackView.addArrangedSubview(numericButtons[0])\n        \n        subStackView.addArrangedSubview(parenthesis1)\n        subStackView.addArrangedSubview(parenthesis2)\n        subStackView.addArrangedSubview(squareroot)\n                \n        subStackView.addArrangedSubview(addButton)\n        subStackView.addArrangedSubview(subtractButton)\n        subStackView.addArrangedSubview(multiplyButton)\n        subStackView.addArrangedSubview(divideButton)\n        \n        \n        subStackView.addArrangedSubview(exponentButton)\n        subStackView.addArrangedSubview(exponentButton2)\n        subStackView.addArrangedSubview(exponentButton4)\n        \n        subStackView.addArrangedSubview(deleteButton)\n        \n    }\n\n    func createStackView(axis: NSLayoutConstraint.Axis) -> UIStackView {\n        let stackView = UIStackView()\n        stackView.axis = axis\n        stackView.alignment = .fill\n        stackView.distribution = .fillProportionally\n        return stackView\n    }\n\n    func insertText(_ string: String) {\n        guard let range = target?.selectedRange else { return }\n\n        if let textField = target as? UITextField, textField.delegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) == false {\n            return\n        }\n\n        if let textView = target as? UITextView, textView.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: string) == false {\n            return\n        }\n\n        target?.insertText(string)\n    }\n}\n\n// MARK: - UITextInput extension\n\nextension UITextInput {\n    var selectedRange: NSRange? {\n        guard let textRange = selectedTextRange else { return nil }\n\n        let location = offset(from: beginningOfDocument, to: textRange.start)\n        let length = offset(from: textRange.start, to: textRange.end)\n        return NSRange(location: location, length: length)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

这非常有效。

\n