1

I am trying to make a custom keyboard to replace the native iOS keyboard in my React Native app. However, I am having trouble making the Swift delegation pattern work when I connect it to React Native. Does anyone know what I can do?

I made a test app entirely in Swift (programmatically) to make sure that the custom keyboard works and the button actions register (they do). However, when I connect this working Swift keyboard to React Native, the buttons stop working. The keyboard appears normally when I click on the text input (for now, this is also made in Swift but this will change soon), but the buttons won't register at all (a print statement doesn't work).

I also tried switching from the delegate pattern to just using callbacks/functions. This time, the buttons register (print statement works), but the text input is never updated and any variable I use to hold the button values is reset.

KeyboardViewManager.swift- In the test app, this was the viewcontroller.


class KeyboardViewManager: RCTViewManager {
  let textField: UITextField = UITextField(frame: CGRect(x: 80, y: 134, width: 255.00, height: 78.00));

  override func view() -> UIView! {
    // initialize custom keyboard
    let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 375, height: 440))

    // the view controller will be notified by the keyboard whenever a key is tapped
    keyboardView.delegate = self as? KeyboardDelegate 

    textField.inputView = keyboardView

    return textField
  }


  func keyWasTapped(character: String) {
      if (character == "<") {
        textField.deleteBackward()
      } else {
        textField.insertText(character)
      }
  }


  func closeIOSKeyboard() {
      textField.endEditing(true)
  }

}

The class for the custom Keyboard


protocol KeyboardDelegate: class {
  func keyWasTapped(character: String)
  func closeIOSKeyboard()
}

class Keyboard: UIView  {

  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 makeButtonWithText(text:String, x:Int, y:Int, width:Int, height:Int, fontSize:CGFloat = 24, bgColor:UIColor = UIColor.clear) -> UIButton {
    let myButton = UIButton(type: UIButton.ButtonType.system)
    myButton.frame = CGRect(x: x, y: y, width: width, height: height)

    myButton.setTitle(text, for: UIControl.State.normal)
    myButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
    myButton.titleLabel?.font = .systemFont(ofSize: fontSize)

    myButton.backgroundColor = bgColor

    myButton.addTarget(self,
                       action: #selector(keyTapped),
                       for: .allEvents
    )
    return myButton
  }

  func initializeSubviews() {
    let view = UIView()
    view.backgroundColor = UIColor(red: 42/255, green: 41/255, blue: 39/255, alpha: 1)
    view.addSubview(makeButtonWithText(text: "1",x: 40,y: 40,width: 85,height: 37))

    // similar code for other buttons here

    view.addSubview(makeButtonWithText(text: "OK",x: 0,y: 340,width: 375,height: 50,
                                       fontSize: 15, bgColor: UIColor(red: 15/255, green: 154/255, blue: 142/255, alpha: 1)
    ))

    self.addSubview(view)
    view.frame = self.bounds
  }

  @objc
  @IBAction func keyTapped(sender: UIButton) {

    KeyboardViewManager().keyTapped(sender: sender, character: sender.titleLabel!.text!)

    // When a button is tapped, send that information to the
    // delegate (ie, the view controller)

    self.delegate?.keyWasTapped(character: sender.titleLabel!.text!)
  }


  @objc
  @IBAction func closeKeyboard(sender: UIButton) {
    // When a ok is tapped, close the keyboard
    self.delegate?.closeIOSKeyboard()
  }

}



Note: I feel like the issue may have something to do with using RCTViewManager instead of viewController to manipulate a UIView. Unfortunately, I'm new to Swift and React Native, and I'm not quite sure how RCTViewManager works!

I expect the text input to be updated each time a button is clicked on the keyboard. Instead, when the buttons are clicked, nothing happens. Fortunately, the keyboard does appear with the correct stylings.

Edit: Here is sample code for my React-Native App (not my actual app, but it's an example of how I'm connecting between Swift and React Native)


import React, {Fragment} from 'react';
import {
  View,
  requireNativeComponent,
} from 'react-native';

const CustomKeyboard = requireNativeComponent("KeyboardView");

import {
  Header,
  LearnMoreLinks,
  Colors,
  DebugInstructions,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

const App = () => {
  return (
    <View style={{flex: 1, alignItems: "stretch"}}>
      <CustomKeyboard style={{flex: 1, alignItems: "center", justifyContent: "center", position: 'relative', top: -100}}/>

    </View>
  );

Deanna
  • 26
  • 2
  • To clarify, I didn't include my code for the bridge files, but I already connected the native module to my React Native App, and can make the keyboard appear. The buttons that were made via the delegation pattern aren't working tho. – Deanna Aug 08 '19 at 16:03
  • Where is the code that you use in React Native? – hong developer Aug 09 '19 at 14:36
  • I just edited the description with an example of it! I can't share the exact application code, but this is how I use it. – Deanna Aug 09 '19 at 16:19

0 Answers0