IOS自定义键盘(swift/Objc)

本文详细介绍了一种基于策略模式的自定义键盘实现方案,包括数字键盘、随机数字键盘及英文键盘的创建与切换,通过Swift语言展示了如何为UITextField设置自定义的InputView,以及如何响应键盘上的按钮点击事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图

QQ20200527-152722-HD.gif

自定义键盘的核心思想

  • 设置UITextFiled 的InputView
  • 切换键盘的思路为重新设置UITextFiled 的InputView然后再调用textFiled?.reloadInputViews()
    *剩下的就是按键的布局与代理设置了

swift版本采用策略模式实现,Objc版本使用常规模式实现

  • 策略模式请参看另一编文章https://blog.youkuaiyun.com/d06110902002/article/details/75642548

swift版本的策略模式实现的角色划分如下:

  • 策略管理类–键盘管理类KeyboardMgr
  • 通用策略类–键盘基类KeyboardBaseView
  • 具体的策略类–数字键盘、随机数字键盘、英文键盘
    ##具体的源码如下:
import UIKit

class KeyboardMgr: UIView {

    var keyboard : KeyboardBaseView?
    static let shareInstace = KeyboardMgr()
    
    lazy var keyboardInstanceDict : [String : KeyboardBaseView] = Dictionary()
    
    func setInputMethodKeyboard(keyboardview keyboard : KeyboardBaseView,
                                inputView textfiled:UITextField,
                                onKeyClickListener listener:OnKeyListener) {
        self.keyboard = keyboard
        self.keyboard?.createView(inputView: textfiled, addOnClickListener: listener)
        keyboardInstanceDict[keyboard.description] = keyboard
    }

}

  • 策略基类源码:
import UIKit

@objc protocol OnKeyListener {
    @objc optional func onClick(button view:UIButton);
    
    
    /// 文本观察监听接口
    /// - Parameters:
    ///   - view: 被观察的对象
    ///   - bStr: 观察之前的文本
    ///   - cStr: 当前u文本
    ///   - aStr: 编辑之后最终的文本
    @objc optional func addTextWatch(button view:UIButton,
                                     beforeText bStr:String?,
                                     curText cStr:String?,
                                     afterText aStr:String?);
    
}

class KeyboardBaseView: UIView {
    
    var textFiled       : UITextField?
    let DELETE          : NSInteger = 19;
    let FINISH          : NSInteger = 21;
    let ABC             : NSInteger = 22;
    let CAPTIAL         : NSInteger = 23;
    let SWITCH_TYPE     : NSInteger = 24;
    let SEARCH          : NSInteger = 25;
    let SPACE           : NSInteger = 98;
    
    
    var onClickListener : OnKeyListener?
    lazy var beforeText : String = String.init()
    lazy var curText    : String = String.init()
    lazy var afterText  : String = String.init()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public func createView(inputView targetView:UITextField,addOnClickListener listener:OnKeyListener){
        self.textFiled = targetView;
        targetView.inputView = self
        self.onClickListener = listener
    }
    
    func createKey(titleTxt title:String,posX x:CGFloat, posY y:CGFloat, width w:CGFloat,hight h : CGFloat,forId id:NSInteger)->Void{
        self.createKey(titleTxt: title, posX: x, posY: y, width: w, hight: h, forId: id, normalImg: nil, highLightimg: nil)
    }
    
    func createKey(titleTxt title:String,
                   posX x:CGFloat,
                   posY y:CGFloat,
                   width w:CGFloat,
                   hight h : CGFloat,
                   forId id:NSInteger,normalImg norBgImg:String?, highLightimg himg:String?)->Void{
        
        let btnKey = UIButton();
        btnKey.frame = CGRect.init(x: x, y: y, width: w, height: h);
        self.addSubview(btnKey)
        btnKey.tag = id
        btnKey.setTitle(title, for: .normal)
        btnKey.setTitleColor(UIColor.black, for: .normal)
        btnKey.addTarget(self, action: #selector(onClickListener(button:)), for: .touchUpInside)
        guard let nImg = norBgImg else{
            btnKey.layer.cornerRadius = 5.0
            return
        }
        btnKey.setBackgroundImage(UIImage.init(named: nImg), for: .normal)
        guard let hImg = himg else{
            return
        }
        btnKey.setBackgroundImage(UIImage.init(named: hImg), for: .highlighted)
        
    }
    
    @objc func onClickListener(button:UIButton) {
        switch button.tag {
            case (0...10),(100...126):
                if self.onClickListener != nil {
                    self.onClickListener!.onClick?(button: button)
                }
                self.afterText.append(button.titleLabel!.text!)
                break;
                
            case ABC:
                switchKeyboardType()
                break;
            
        case SEARCH:
            
            break;
            
        case SWITCH_TYPE:
            switchKeyboardType()
            break;
            
        case CAPTIAL:
            switchCaptial(button: button)
            break;
                
            case DELETE:
                if !self.afterText.isEmpty{
                    let index = self.afterText.count - 1
                    self.afterText = self.afterText.prefix(index).description
                }
                break;
                
            case FINISH:
                hideKeyboard()
                break;
                
            default:
                break;
        }
        
        if self.onClickListener != nil && !(21...30).contains(button.tag){
            
            self.onClickListener?.addTextWatch?(button: button,
                                            beforeText: self.beforeText,
                                               curText: button.titleLabel!.text,
                                             afterText: self.afterText)
            self.beforeText = self.afterText;
        }
        
    }
    
    func hideKeyboard() {
        self.textFiled?.endEditing(true)
    }
    
    func switchCaptial(button view : UIButton) {
        
    }
    
    func switchKeyboardType() {
        
    }


}

  • 数字键盘类
import UIKit

class NumberKeyboard: KeyboardBaseView {
    
    lazy var logoLabel:UILabel = UILabel()
    var colSpace : CGFloat = 5.0;
    var rowSpace : CGFloat = 5.0
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.gray
        createLogoView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func createView(inputView targetView: UITextField,addOnClickListener listener:OnKeyListener) {
        super.createView(inputView: targetView,addOnClickListener: listener)
        for view in self.subviews{
            view.removeFromSuperview()
        }
        let width = (self.frame.size.width - self.colSpace * 4) / 3
        let height = (self.frame.size.height - self.logoLabel.frame.size.height - self.rowSpace * 4 ) / 4
        for i in 1..<10{
            
            let indexColSpace = self.colSpace * CGFloat((i - 1) % 3)
            let indexWidth = width * CGFloat((i - 1) % 3)
            let x = self.colSpace + indexColSpace +  indexWidth
            
            let indexRowSpace = self.rowSpace * CGFloat((i - 1) / 3)
            let indexRowHeight = height * CGFloat((i - 1) / 3)
            let y = 44 + indexRowSpace + indexRowHeight
            
            createKey(titleTxt: String.init(format: "%d", i),
                      posX: x,
                      posY: y,
                      width: width,
                      hight: height,
                      forId: i,
                  normalImg: "anniu1.png",
               highLightimg: "anniu1_select.png")
        }
        
        createKey(titleTxt: "ABC",
                             posX: self.colSpace,
                             posY: self.logoLabel.frame.size.height + self.rowSpace * 3 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值