0

I'm using Xcode 7.3.1 to write an app in Swift to run on iOS 9.3. I'm creating UITextFields programmatically, but can't get them to accept focus when I click in one of them. Here's how I create each UITextField:

self.hoursField = UITextField()
self.hoursField!.borderStyle = UITextBorderStyle.Bezel
self.hoursField!.canBecomeFirstResponder()
self.hoursField!.canBecomeFocused()
self.hoursField!.delegate = self
self.hoursField!.enablesReturnKeyAutomatically = true
self.hoursField!.translatesAutoresizingMaskIntoConstraints = false
self.hoursField!.userInteractionEnabled = true

The UITextFields appear exactly where I want them and look exactly as I want them to look, I just can't get them to accept focus so I can edit the text in the field.

I am implementing all the methods in the UITextFieldDelegate protocol, and returning true from all those methods that return a boolean.

Can anyone explain what I'm doing wrong, or not doing?

Each text field is being created and added to a custom subclass of UIView that contains a couple of UILabels in addition to the UITextField. Here's the relevant part of the custom view's init method that creates the text field:

init(frame: CGRect, charge: (code:String, note:String?, hours:Int)) {
    super.init(frame: frame)

    // Create the hours UITextField
    self.hoursField = UITextField()
    self.hoursField!.borderStyle = UITextBorderStyle.Bezel
    self.hoursField!.canBecomeFirstResponder()
    self.hoursField!.canBecomeFocused()
    self.hoursField!.contentVerticalAlignment = UIControlContentVerticalAlignment.Center
    self.hoursField!.delegate = self
    self.hoursField!.enablesReturnKeyAutomatically = true
    self.hoursField!.font = UIFont.systemFontOfSize(14)
    self.hoursField!.keyboardType = UIKeyboardType.NumberPad
    self.hoursField!.returnKeyType = UIReturnKeyType.Done
    self.hoursField!.text = String(charge.hours)
    self.hoursField!.textAlignment = NSTextAlignment.Right
    self.hoursField!.translatesAutoresizingMaskIntoConstraints = false
    self.hoursField!.userInteractionEnabled = true

    // Add it to the view
    self.addSubview(self.hoursField!)

    // Create its layout constraints
    let hoursTopMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: self.hoursField!, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.codeLabel!, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    let hoursLeftMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: self.hoursField!, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.codeLabel!, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: self.hourFieldIndent)
    let hoursRightMarginConstraint:NSLayoutConstraint = NSLayoutConstraint(item: self.hoursField!, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.hoursField!, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: self.hourFieldWidth)

    // Add the layout constraints to the view
    self.addConstraints([hoursTopMarginConstraint, hoursLeftMarginConstraint, hoursRightMarginConstraint])

A stripped-down version of my app that shows the problem I'm having can be downloded from https://github.com/ThomBrando/TextFieldDemo.git

Thom
  • 53
  • 9
  • This is the same old "view outside of its superview" problem that has been answered so often on Stack Overflow. I've marked as a duplicate so you have a link, and I've explained in an answer below how to clean up your code so that the text views become tappable. – matt Aug 29 '16 at 03:03

5 Answers5

0

Have you tried

self.hoursField!.becomeFirstResponder() 
Amloelxer
  • 752
  • 2
  • 8
  • 20
  • Yes, but that puts the focus in the first UITextField as soon as the app comes up. It doesn't wait until I click in a UITextField I want to edit. What I really need (maybe) is for one of the delegate methods to be called when I click in one of the UITextFields, so I can then call becomeFirstResponder. – Thom Aug 28 '16 at 21:47
  • So when you click on the textfield what happens? – Amloelxer Aug 28 '16 at 21:49
  • Absolutely nothing. – Thom Aug 28 '16 at 21:50
  • I think it might be something with how you place or add your textfield to your view then. It should become the first responder when you click on it. How are you adding it programmatically to the screen? – Amloelxer Aug 28 '16 at 21:52
  • Each UITextField is a subview of a custom subclass of UIView that also contains a couple of labels. The part of the custom view's init method that creates the text field is as follows: (hmmm, can't seem to insert a return in this field. i'll try adding the code to my original question) – Thom Aug 28 '16 at 22:00
  • I've added a link to a Github repository with a stripped-down version of my app that shows the problem I'm having. – Thom Aug 28 '16 at 23:09
0

When I implement a texfield programmatically all that I have to do is instantiate the texfield. let field = UITextFeild() set its delegate let field.delegate = self

extension UIViewController: UITextFieldDelegate {
public func textFieldShouldReturn(textField: UITextField) -> Bool {
    self.view.endEditing(true)
    return false
  }
}

I have never used the two lines you had in your attempt. .canBecomeFirstResponder .conBecomeFocused .enablesReturnKeyAutomatically I would suggest removing those.

Then if you are trying to get the keyboard to dismiss when anywhere else is tapped on the screen I would suggest adding this wrapped up in an extension so you can add it anywhere.

 extension OnboardingPage {
func hideKeyboardWhenTappedAround() {
    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    view.addGestureRecognizer(tap)
}

Then just call hideKeyboardWhenTappedAround() in your viewDidLoad that you want that action on.

Hope that helps. :)

Dan Leonard
  • 3,325
  • 1
  • 20
  • 32
  • Removing the calls to .canBecomeFirstResponder, .canBecomeFocused, and .enablesReturnKeyAutomatically makes no difference. – Thom Aug 28 '16 at 22:23
  • I've added a link to a Github repository with a stripped-down version of my app that shows the problem I'm having. – Thom Aug 28 '16 at 23:09
  • Do you wanna add a link to the project here – Dan Leonard Aug 29 '16 at 00:12
0

Can you give us a little more info? Like what's the frame of your UITextfield? Because i copied your code and i have the same issue but it was fine for me when i added a frame for UITextfield. Also just want to make sure you're adding the textfield as a subview to it's parent view.

Also I would recommend trying on a device if you have one, the simulator sometimes bugs out and things don't work as expected

  • I've added more to my original post to show how I'm creating the text fields. Also, I have tried this on a real device, with the same lack of results. – Thom Aug 28 '16 at 22:19
  • I've added a link to a Github repository with a stripped-down version of my app that shows the problem I'm having. – Thom Aug 28 '16 at 23:09
0

I think this happens because you are testing it on the simulator with the keyboard disabled. The simulator will then use your computer's keyboard and won't show the iOS keyboard.

Could you try pressing Cmd-K when you select the UITextField?

Jordi Bruin
  • 1,588
  • 1
  • 11
  • 20
  • I've tested this in the simulator with the keyboard disabled and with the keyboard enabled, and I've tested it on a real iPhone. – Thom Aug 28 '16 at 23:08
  • 1
    I've added a link to a Github repository with a stripped-down version of my app that shows the problem I'm having. – Thom Aug 28 '16 at 23:09
0

The problem turns out to be this line:

let frame:CGRect = CGRect(x: 0, y: totalContentHeight, width: 0, height: 0)
let chargeView:CustomView = CustomView(frame: frame, charge: charge)

So your CustomView has zero width, zero height — zero size. Thus, none of its subviews is touchable. The text fields are its subviews. Thus, they are not touchable. They are visible, because the CustomView does not clip to its bounds; but they are outside their superview, so they are not touchable.

To prove this, just change the first line to this:

let frame:CGRect = CGRect(x: 0, y: totalContentHeight, width: 500, height: 100)

Those are not the "right" numbers, but that doesn't matter. The point is, you will find you can now tap on the text field and type in it! So that should give you enough of a clue to get started.

matt
  • 515,959
  • 87
  • 875
  • 1,141