2

New to Swift.

When a user clicks on a text field to begin typing, is there a way to disable all user interaction other than typing into that text field? I want it so that the user is unable to click outside the text field, and should press the return key to dismiss keyboard, where user interaction is enabled again (I have the dismiss keyboard part set up).

I know that the isUserInteractionEnabled function can stop all interaction, but I still want the user to be able to interact with the keyboard.

Thanks

hamsternik
  • 1,376
  • 3
  • 18
  • 26
brownmamba
  • 173
  • 1
  • 1
  • 16
  • Should not be automatic, you need to code it like that, disabling programmatically all other functionality. – Mago Nicolas Palacios Jan 09 '17 at 20:49
  • right. that's what im wondering how to do. I know userInteractionEnabled can stop all interaction but i still want the user to be able to interact with the keyboard – brownmamba Jan 09 '17 at 20:53
  • For Example, for a UI Button, you should do yourButtonName.isEnabled = false – Mago Nicolas Palacios Jan 09 '17 at 21:05
  • right that's for buttons, but i want to disable user interaction except for interacting with the keyboard – brownmamba Jan 09 '17 at 21:10
  • Do you mean to disable all interaction with UI except only the keyboard for the concrete text field? – hamsternik Jan 09 '17 at 21:12
  • Maybe there is a way, check this: http://stackoverflow.com/questions/29068243/swift-how-to-disable-user-interaction-while-touch-action-is-being-carried-out But with my way you can do it as well, you just need to have an outlet for all intractable parts of your App and change isEnabled to false – Mago Nicolas Palacios Jan 09 '17 at 21:12
  • @Hamsternik Sorry if i wasn't too clear but yes this is what i mean! – brownmamba Jan 09 '17 at 21:13
  • 1
    @brownmamba since you have not accepted an answer, I believe you are still looking for a answer. I don't have a coded solution but why not mask your entire view with another view when the keyboard comes out? This also allows you to give a color to the mask view (with say opacity of 0.4) that will help users understand why nothing would happen on clicking outside the keyboard area. You can use UIKeyboardWillShowNotification and UIKeyboardWillHideNotification to calculate the size, and show/hide the mask view. – Bhavik Bhagat Jan 10 '17 at 00:51
  • @BhavikBhagat how would i go about masking my view with another view when an event occurs? – brownmamba Jan 10 '17 at 22:33
  • @brownmamba I guess you mean "keyboard show" event. You can register for two keyboard notifications: `[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];`. Implement keyboardWillShow method in which you can unhide a previously hidden view that covers the rest of the screen. Implement keyboardWillHide method in which you can hide the same view. – Bhavik Bhagat Jan 10 '17 at 22:48

2 Answers2

1

So, the first idea, which came up to me is disabling every UI element into your view while you're focused on the UITextField instance.

Create a function, which will obtain a UI element as an argument (UITextField for ex). In the function's body start to check every UI element and cyclically disable everyone, which will not equal to the passed argument. You can verify your text field for the type and text additionally.

Here's draft of the function's body:

func disableAll(exceptInput element: UITextField) {
    for item in self.view.subviews {
        if item != element {
            item.isUserInteractionEnabled = false
        } else {
            item.isUserInteractionEnabled = true
        }
    }
}

And perform this method in the text field action, for ex. in the onDidStart.

And, obviously, don't forget about enabling all elements for user interaction. The code is simple:

func enableAll() {
    for item in self.view.subviews {
        item.isUserInteractionEnabled = true
    }
} 

This method you can perform on the onDidEnd IBAction for every UITextField. The last step is necessary if you want to run the normal application behavior.

hamsternik
  • 1,376
  • 3
  • 18
  • 26
  • This is very close to what i am trying to achieve. I'm working with table view cells and have one textField element to control all the cells. So with your answer the user could press on another cell's textField and interaction would be enabled. Is there a way to just focus on one cell's textField? So they can't even click on other textFields? – brownmamba Jan 10 '17 at 00:00
0

The behavior you describe is can be accomplished by manipulating the Boolean isEnabled value if UI elements. There are a couple of steps to make this smooth and user friendly.

Just good practice, and not required for this example, but I like to make extension of the MyViewController, to subscribe/unsubscribe to keyboard notifications and so on in it, like so:

import Foundation
import UIKit

extension MyViewController {            

    //MARK: Subscribing/Unsubribing to NotificationCenter.
    func subcribeToKeyboardNotifications(){    
         NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    func unsubscribeToKeyboardNotifications(){
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    //MARK: Screen manipulation methods, to move the UIView up when the bottom text field is editing.
    func keyboardWillShow(_ notification: Notification) {
        if bottomTextField.isEditing {
            view.frame.origin.y =  getKeyboardHeight(notification) * -1
        }
    }

    func keyboardWillHide(_ notification: Notification) {
        if bottomTextField.isEditing {
            view.frame.origin.y = 0
        }
    }

    //MARK: Value returning method to calculate keyboard height.
    private func getKeyboardHeight(_ notification: Notification) -> CGFloat {
        let userInfo = (notification as NSNotification).userInfo!
        let keyboardSize = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue
        return keyboardSize.cgRectValue.height
    } 
}

Next, in MyViewController, I set the keyboard to resignToFirstResponder() when the return key is tapped, and I make sure to set my UITextFieldDelegates.

import Foundation
import UIKit

class MyViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var someButton: UIButton!
    @IBOutlet weak var topTextField: UITextField!
    @IBOutlet weak var bottomTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        //Set the delegates to self, it this example.
        topTextField.delegate = self
        bottomTextField.delegate = self
        enableUIElements(true)
    }

    //Delegate function to type stuff into the text field.
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        enableUIElements(false)
        var newText = textField.text! as NSString
        newText = newText.replacingCharacters(in: range, with: string) as NSString
        let textSize: CGSize = newText.size(attributes: [NSFontAttributeName: textField.font!])
        return textSize.width < textField.bounds.size.width
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder() //Dismiss the keyboard.
        enableUIElements(true) //enable the UI elements.
        return true
    }

    //Create a function to enable/disable UI elements.
    func enableUIElements(_ enable: Bool){
        someButton.isEnabled = enable
        //TODO: add other elements here.
    }
}

Note that last function!!! Use it to enable/disable other elements while the keyboard is active, as I've shown.

That should get you where you need to go :)

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52