iOS Crea una tastiera in-app personalizzata


Esempio

GIF animate con tastiera personalizzata

Questa è una tastiera in-app di base. Lo stesso metodo potrebbe essere utilizzato per creare praticamente qualsiasi layout di tastiera. Ecco le principali cose che devono essere fatte:

  • Crea il layout della tastiera in un file .xib, il cui proprietario è una classe Swift o Objective-C che è una sottoclasse UIView .
  • Dì a UITextField di usare la tastiera personalizzata.
  • Utilizzare un delegato per comunicare tra la tastiera e il controller della vista principale.

Creare il file di layout della tastiera .xib

  • In Xcode, vai su File> Nuovo> File ...> iOS> Interfaccia utente> Visualizza per creare il file .xib.
  • Ho chiamato il mio Keyboard.xib
  • Aggiungi i pulsanti di cui hai bisogno.
  • Utilizza i vincoli di layout automatico in modo che, indipendentemente dalle dimensioni della tastiera, i pulsanti vengano ridimensionati di conseguenza.
  • Impostare il proprietario del file (non la vista root) come classe della Keyboard . Questa è una fonte comune di errore. Creerai questo corso nel passaggio successivo. Vedi la nota alla fine.

Creare il file della tastiera della sottoclasse .swift UIView

  • In Xcode vai su File> Nuovo> File ...> iOS> Sorgente> Cocoa Touch Class per creare la classe Swift o Objective-C. Scegli UIView come superclasse per la classe appena creata

  • Ho chiamato il mio Keyboard.swift (classe Keyboard in Objective-C)

  • Aggiungi il seguente codice per Swift:

      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 = NSBundle.mainBundle().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(sender.titleLabel!.text!) // could alternatively send a tag value
          }
      
      }
    
  • Aggiungere il seguente codice per Objective-C:

    Keyboard.h File

    #import <UIKit/UIKit.h>
    
    // The view controller will adopt this protocol (delegate)
    // and thus must contain the keyWasTapped method
    @protocol KeyboardDelegate<NSObject>
    - (void)keyWasTapped:(NSString *)character;
    @end
    
    @interface Keyboard : UIView
    @property (nonatomic, weak) id<KeyboardDelegate> delegate;  
    @end
    

    Keyboard.m File

    #import "Keyboard.h"
    
    @implementation Keyboard
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        [self initializeSubviews];
        return self;
    }
    
    - (id)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        [self initializeSubviews];
        return self;
    }
    
    - (void)initializeSubviews {
        NSString *xibFileName = @"Keyboard"; // xib extention not included
        UIView *view = [[[NSBundle mainBundle] loadNibNamed:xibFileName owner:self options:nil] firstObject];
        [self addSubview:view];
        view.frame = self.bounds;
    }
    
    // MARK:- Button actions from .xib file
    
    -(IBAction)keyTapped:(UIButton *)sender {
        // When a button is tapped, send that information to the
        // delegate (ie, the view controller)
        [self.delegate keyWasTapped:sender.titleLabel.text]; // could alternatively send a tag value
    }
    
    @end
    
  • Controlla le azioni di trascinamento dai pulsanti per richiamare i pulsanti nel file .xib e il metodo @IBAction nel proprietario Swift o Objective-C per agganciarli tutti.
  • Si noti che il protocollo e il codice del delegato. Vedi questa risposta per una semplice spiegazione su come funzionano i delegati.

Configura il View Controller

  • Aggiungi un UITextField allo storyboard principale e collegalo al controller di visualizzazione con un IBOutlet . Chiamalo textField .

  • Usa il seguente codice per il View Controller in Swift:

      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)
          }
      }
    
  • Utilizzare il seguente codice per Objective-C:

    .h File

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    
    @end
    

    .m File

    #import "ViewController.h"
    #import "Keyboard.h"
    
    @interface ViewController ()<KeyboardDelegate>
    
    @property (nonatomic, weak) IBOutlet UITextField *textField;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    
        // initialize custom keyboard
        Keyboard *keyboardView = [[Keyboard alloc] initWithFrame:CGRectMake(0, 0, 0, 300)];
        keyboardView.delegate = self; // the view controller will be notified by the keyboard whenever a key is tapped
    
        // replace system keyboard with custom keyboard
        self.textField.inputView = keyboardView;
    }
    
    - (void)keyWasTapped:(NSString *)character {
        [self.textField insertText:character];
    }
    
    @end
    
  • Si noti che il controller della vista adotta il protocollo KeyboardDelegate che abbiamo definito sopra.

Errore comune

Se si verifica un errore EXC_BAD_ACCESS , è probabilmente perché si imposta la classe personalizzata della vista come Keyboard anziché eseguire questa operazione per il proprietario del file del pennino.

Seleziona Keyboard.nib e quindi scegli Proprietario file.

schermata del proprietario del file

Assicurarsi che la classe personalizzata per la vista principale sia vuota.

screenshot di vista radice vuota

Gli appunti

Questo esempio proviene originariamente da questa risposta di Overflow dello stack .