Prevent UITextField editing but detect taps - ios

I have a UITextField and I am trying to detect the taps on it and prevent user typing input at the same time. The scenario is, I'm gonna use an alert view to make the user select an option and write it inside UITextField rather than user typing it using keyboard.
I tried using in viewDidLoad():
myTextField.delegate = self
myTextField.isEnabled = true
myTextField.isUserInteractionEnabled = false
// for keyboard
myTextField.inputView = UIView()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didRecognizeTapGesture(_:)))
myTextField.addGestureRecognizer(tapGesture)
However this tap gesture doesn't work:
private dynamic func didRecognizeTapGesture(_ gesture: UITapGestureRecognizer) {
print("YYYY")
let point = gesture.location(in: gesture.view)
guard gesture.state == .ended, taxableField.frame.contains(point) else { return }
//doSomething()
}
Then I tried making userInteractionEnabled true and this time:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField == myTextField {
print("XXXX")
return true
}
return true
}
This worked, however now I can long-press and paste into the textfield, so it is active, it's just not showing the keyboard this way.
So any of the ways I have tried don't seem convenient. What do you suggest for achieving such thing?

So, to create a UIPickerView and add it as your inputView, you need a delegate and a datasource. For this example, I'm going to assume that your VC will fill all of these roles. I usually split these out into custom classes, but I want to keep this simple:
// Data source for your picker view
var pickerViewData : [String]?
var myPickerView = UIPickerView()
#IBOutlet myTextField : UITextField!
func viewDidload() {
myPickerView.delegate = self
myPickerView.dataSource = self
myTextField.delegate = self
myTextField.inputView = pickerView
}
And then, to update your UITextField, whenever your picker view is used, implement the correct delegate method (It won't build unless you implement the method, regardless):
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
myTextField.text = pickerViewData![pickerView.selectedRow(inComponent: 0)]
}
And that's it! You also have to implement some other UIPickerView and UITextField delegate and datasource methods; I'm assuming you can figure out how to do this, if you don't know already.

You can take a UIButton over the UITextField and align its leading, trailing, top and Bottom with the UITextField.
Then add an action for the button.
Disable the TextField.

You can use UIPickerView to implement your function. If the picker must be a AlertView, you can replace the UITextField with a UILabel and put a UIButton upon it then you can implement the custom action in the UIButton callback and display the selection in the UILabel.

create a custom UIViewController which background color is clear and add a UIPickerView to show options. Show the UIViewController (overlay on top of current UIView) while UITextField is focus. So, you can do your handles within custom UIViewController.

Related

IOS Swift TextView UITapGestureRecognizer with tab to move cursor

i used default keyboard and custom keyboard
if textview touch event when custom keyboard is showing, change to default keyboard
class ReplyPage: UIViewController ,UITextViewDelegate,EmojiKeyboardDelegate,UIGestureRecognizerDelegate{
#IBOutlet weak var replyArea: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
replyArea.delegate=self
emojiView.delegate = self
replyPage = self
let tapTerm = UITapGestureRecognizer(target: self, action: #selector(textViewTouch))
tapTerm.delegate = self
replyArea.addGestureRecognizer(tapTerm)
more code...
}
#objc func textViewTouch(){
if isEmoji{
replyArea.inputView = nil
replyArea.reloadInputViews()
isEmoji = false
emojiButton.setImage(UIImage(named:"emoji"), for: UIControlState.normal)
}else{
replyArea.reloadInputViews()
replyArea.becomeFirstResponder()
}
}
}
this code is worked
but can't move cursor in textview
default tab is move cursor
but UITapGesture override this so can't work
how to use Both default tab and UITapGesture
Can i Listen Textview Touch without UITapGesture?
can't textViewDidBeginEditing()
TextView Tap do not call textViewDidBeginEditing after first open custom keyboard.
because First Custom Keyboard Open already call textViewDidBeginEditing
Please add protocol TextViewDelegate in your viewController .
And add
self.replyArea.delegate = self

Trouble with tap gestures

I have a tap gesture on a UIImageView within a class that extends UITableViewCell. This code should work, I don't see why it doesn't. The only thing I am iffy on is what the "target" should be - should it be the profileImage, or the overall ViewController that things are in?
#IBOutlet weak var profileImage: UIImageView!
var vc: TweetsViewController? = nil
override func awakeFromNib() {
super.awakeFromNib()
let tapGester = UITapGestureRecognizer(target: vc, action: Selector("handleTapGester:"))
tapGester.delegate = self
profileImage.addGestureRecognizer(tapGester)
}
func handleTapGester(tapGesture: UITapGestureRecognizer) {
print("*******hi*******")
vc?.performSegueWithIdentifier("showProfile", sender: nil)
}
And for the record, as this may seem like a relevant error, I initialize vc when the table cell loads.
The target should be the object that will handle the tap gesture and the handleTapGester function should be inside the object class you specified as the target, not inside the UITableViewCell subclass.
You also need to enable user interaction on the UIImageView by saying:
imageView.userInteractionEnabled = true
Why not just add a tap gesture recogniser to the view, then when called query indexPathForRowAtPoint to find out which cell is being tapped?
If you know the cell you can then determine if the UIImage is being tapped and make your call to performSegueWithIdentifier from there.
If it's tapped on a cell that you're not interested in let it fall through and be handled by the table by calling cancelsTouchesInView on the recogniser.

how to show pickerview from another nib file to textfields inputview main storyboard

first of, I'm using xcode7.1 swift 2.
I have two nib/xib files, first is the main nib/xib and second one is pickview nib/viewcontroller file. How do I show the pickview nib/viewcontroller when textfield is tapped?
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
var readableTextfield: Bool? = true
textField.inputView = pickerViewCustom
return readableTextfield!
}
pickerViewCustom is a UIPickerView from pickview nib/viewcontroller
What I'm trying to to make is when a user is filling up a form, a UIPickerview will popup and will select values from an array and display the selected value to the textview. Am I doing it right?
Try set inputView when initializing UITextField, such as viewDidLoad:
func viewDidLoad() {
...
textField.inputView = pickerViewCustom
...
}

How do I activate an inputView using a UIButton in Swift?

I am attempting to have a UIDatePicker come up as a keyboard when the user hits a UIButton. I was able to get it to work with a textfield, but I don't like how the cursor is visible and the user could enter in any text if they had an external keyboard. Here is my code:
#IBAction func dateFieldStart(sender: UITextField) {
var datePickerStartView : UIDatePicker = UIDatePicker()
datePickerStartView.datePickerMode = UIDatePickerMode.Time
sender.inputView = datePickerStartView // error when sender is UIButton
}
I tried changing the sender to UIButton but it gave this error on the line that is marked above:
Cannot assign to 'inputView' in 'sender'
I have tried researching it and no one else seems to have had a problem with it. Anyone know how to trigger a UIDatePicker inputView using a UIButton or anything that might work better that the user cannot type into? Thanks!
This is years after the original question, but for anyone who may be looking for solution to this you can subclass UIButton and provide a getter and setter for the inputView property. Be sure to call becomeFirstResponder in the setter and override canBecomeFirstResponder. For example:
class MyButton: UIButton {
var myView: UIView? = UIView()
var toolBarView: UIView? = UIView()
override var inputView: UIView? {
get {
myView
}
set {
myView = newValue
becomeFirstResponder()
}
}
override var inputAccessoryView: UIView? {
get {
toolBarView
}
set {
toolBarView = newValue
}
}
override var canBecomeFirstResponder: Bool {
true
}
}
let tempInput = UITextField( frame:CGRect.zero )
tempInput.inputView = self.myPickerView // Your picker
self.view.addSubview( tempInput )
tempInput.becomeFirstResponder()
It's a good idea to keep a reference to tempInput so you can clean-up on close
I wanted to do the same thing, I ended up just overlaying a UITextField over the button and using the inputView of that instead.
Tip: set tintColor of the UITextField to UIColor.clearColor() to hide the cursor.
You can create a view for the picker off screen view and move it on screen when you need it. Here's another post on this.

How to dismiss keyboard with multiple UITextField

I'm a noob here and in iOS world. I am having trouble dismiss keyboard on a specific case in my very simple todo list iOS app.
I'd like the keyboard to get dismiss when user taps anywhere outside the current text field or the keyboard itself. So far, I got the keyboard dismisses just fine (thanks to you guys here in stack overflow) when user taps on the UITableView, or most element on my app. HOWEVER, when user taps on another UITextField, the keyboard does not go away.
FYI, here's the list of existing threads I researched so far but have yet to solve this issue.
1) How to dismiss keyboard iOS programmatically
2) Resigning First Responder for multiple UITextFields
3) Dismissing the First Responder/Keyboard with multiple Textfields
4) (a few more at least but I lost track :( )
Here's what I did so far:
(in viewDidLoad())
// Add 'tap' gesture to dismiss keyboard when done adding/editing to-do item
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapOutside:")
tap.cancelsTouchesInView = true
self.view.addGestureRecognizer(tap)
func tapOutside(tapOutside: UIGestureRecognizer) {
// Dismiss keyboard
self.view.endEditing(true)
}
#IBAction func EditingDidBegin(sender: UITextField) {
// Highlight the text field which user is editing
self.highlightTextField(sender, highlight: true)
}
#IBAction func EditingDidEnd(sender: UITextField) {
// Undo text field highlight
self.highlightTextField(sender, highlight: false)
self.view.endEditing(true) // try this option and not working
self.setEditing(false, animated: true) // try this option and not working
sender.resignFirstResponder() // try this option and not working
UIApplication.sharedApplication().becomeFirstResponder() // try this option and not working
... // below is my code to update the todo item
}
I also tried to print out all subviews.isFirstResponder() of my view. All of it return false. I also tried override touchesBegan of my UIViewController, and inside it just calls self.view.endEditing(true) and call its super's. This also does not work.
Please help. :(
TIA!
UPDATE:
You guys are awesome! :D I got it working now thanks to you guys. There were several mistakes / messed up as I'm learning new framework. So here's what I did.
1) I did not set UITextField delegate correctly.
Mistake: I ctrl-draged textfield in xcode and link my viewController as delegate and thought that should work out. I will still need to research and understand better why.
Solution: I removed that ctrl-drag link and explicitly call myTextField.delegate = self in tableView:cellForRowAtIndexPath. And that did it. Thanks #Sidewalker
2) Mistake: I have a mixed of textFieldShouldBeginEditing, etc. and #IBAction func EditingDidBegin. So I got myself into the situation where textFieldShouldBeginEditing got the call, but EditingDidBegin did not get call.
Solution: Once I set the delegate = self explicitly and stick with implementing textField... methods and not use any #IBAction for textField, things just work.
Here's one option... We're going to add a boolean flag to determine whether or not we're in a textField when an edit attempt for another textField begins
Make your class adhere to UITextFieldDelegate
class MyClass: UIViewController, UITextFieldDelegate
Don't forget to set the delegate, we'll add the flag as well
myTextField.delegate = self
var inField = false
Implement "textFieldShouldBeginEditing" and "textFieldDidBeginEditing"
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if inField {
inField = false
return false
}
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
inField = true
}
I prefer tracking things like this rather than identifying subviews as it allows the flag to be utilized elsewhere and cuts down code complexity.
Well the keyboard isn't going away because it doesn't expect to have to. The new UITextField is just becoming the first responder while the other resigns. If you don't want a textField to become the first responder if another is already, you're going to have to cut it off before it gets the chance to. I would try to implement textFieldShouldBeginEditing and figuring out the logic there.
I'm not in love with the way this looks but this should do something along those lines.
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
for subView in self.view.subviews{
if(subView.isKindOfClass(UITextField)){
if(subView.isFirstResponder()){
subView.resignFirstResponder();
return false;
}
}
}
return true;
}
First set all the UITextField (your are creating) delegate as self and create one UITextField member variable. Now implement "textFieldDidBeginEditing" delegate method and assign the textfield to your member UITextField variable. As given below
func textFieldDidBeginEditing(textField: UITextField) {
yourMemberVariable = textField;
}
So now whenever you want to dismiss the keyboard call the dismiss method on "yourMemberVariable" object. It should work !!
What I usually do is implementing this two method:
The first one add a UITapGestureRecognizer to the whole UIViewController view
func hideKeyboard() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
The second one just get called every time the user touch anywhere on the UIViewController's view
func dismissKeyboard() {
self.view.resignFirstResponder()
}
I add the first one to the viewDidLoad method of the UIViewController. Or better yet if you want to use that on all the app just make that an extension for your UIViewController.
How about doing this in viewController, It works for me
func dismissKeyboard() {
//All the textFields in the form
let textFields = [textField1, textField2, textField3, textField4, textField5]
let firstResponder = textFields.first(where: {$0.isFirstResponder ?? false })
firstResponder?.resignFirstResponder()
}

Resources