I want to call an animation when my UITextView is empty and again when it is not empty.
I get the UITextView changes in the delegate method below;
func textViewDidChange(_ textView: UITextView) {
}
However, this checks if the UITextView is empty every time it changes. I only want to call this once.
Is there any method for this?
This delegate is handled by UIKit, therefore is not possible to select when it is called. However, there are these other options according to Apple docs:
func textViewDidBeginEditing(_ textView: UITextView)
func textViewDidEndEditing(_ textView: UITextView)
Related
I want to listen for every text change in UITextView. The setup is very trivial.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(
self,
selector: #selector(textViewDidChangeWithNotification(_:)),
name: UITextView.textDidChangeNotification,
object: nil
)
}
#objc private func textViewDidChangeWithNotification(_ notification: Notification) {
print("Text: \(String(describing: inputTextView.text))")
}
It works OK in most cases, but then I have found some UITextInput's black box magic.
Step 1: 'I' typed. We can see 'I' in the output.
Step 2: Important step. Select all text with double tap on the field.
Step 3: Select 'If' from word suggestions.
And there is no 'If' in the debuggers output. On the other side if the caret will be at the end of the 'I' word and we select 'If' output results are correct.
Is there any way to observe ALL text changes?
I can get text by using:
func textViewDidEndEditing(_ textView: UITextView)
but I need to observe all changes in real time. The other option I always see is to use:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool
but this method is a bad practice to observe changes. If you type two spaces repeatedly iOS will replace first space with dot and obviously will not inform you about this action in this method and a lot of other problems with it.
OK, after a lot of research I've tried RxSwift because I thought that observing text in reactive paradigm framework should succeed in 100% cases. And it worked without any issues!
inputTextView.rx.text.subscribe(onNext: { string in
print("rx: \(string)")
})
So it seems that these guys have found the solution.
https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/iOS/UITextView%2BRx.swift
And here is the solution that gives you information about all text changes despite of auto correction, text selection, and etc..
class ViewController: UIViewController {
#IBOutlet weak var inputTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
inputTextView.textStorage.delegate = self
}
}
extension ViewController: NSTextStorageDelegate {
func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorage.EditActions, range editedRange: NSRange, changeInLength delta: Int) {
print("string: \(textStorage.string)")
}
}
You can use func textViewDidChangeSelection(_ textView: UITextView) to detect the change in selection ?
If you want to listen for every change shouldChangeTextIn is the way to go. You can write conditions to solve the problems associated with it
Swift beginner here. I am having quite a tough time getting my UITextView delegate methods to call. I have looked through many other questions, to no avail.
I have a UITextView set up in a ViewConroller. It looks like this:
There is a UIImageView directly above the UITextView, and everything is wrapped in a navigation controller, should be no big deal.
I made sure to connect the View from the storyboard to my ViewController:
From the storyboard I CTRL+Drag the UITextView right below the class declaration. This produces the line:
#IBOutlet weak var Description: UITextView!
Class declaration:
class ImageTextViewController: UIViewController, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
(I need the other delegates for my NavigationController and UIImageView)
I then declare the delegate as so:
override func viewDidLoad() {
super.viewDidLoad()
self.Description.delegate = self
Now the following delegate method should be called when I finish editing the UITextView. But for some reason it is not firing!
private func textViewDidEndEditing(_ textView: UITextView) -> Bool{
print("we are done editing")
spotDescription.resignFirstResponder()
return true
}
How do I get that to fire properly for my UITextView?
textViewDidEndEditing method do not have return value. You have to write this
func textViewDidEndEditing(_ textView: UITextView) {
print("we are done editing")
}
Jack is right.
In the image titled Storyboard Connection your viewController seems to be titled TextImageViewController, while in the class declaration example is titled ImageTextViewController.
The ViewController in the Storyboard and the ViewController should both be the same.
Андрей is also right.
TextViewDidEndEditing method does not have a return value.
lindanordstrom also makes a good point:
TextViewDidEndEditing shouldn't be private.
I have a textView and i need to update my textView content and save the edited text. In my case everything is working but in the UI edited text is updated.self.taskName data get it from the previous ViewController
In viewDidLoad i was written like this
self.taskNameTextView.text = self.taskName
self.taskNameTextView.delegate = self
In textViewDelegate,
func textViewDidChange(_ textView: UITextView) {
self.taskName = textView.text
}
and button action i have to passed the edited textString and it return successful but not changed updated text in UI.Can you please anyone help me to figure out this problem.
Rather than textViewDidChange please write your code inside
func textViewDidEndEditing(_ textView: UITextView) {
// your code here
}
For more delegate functions of TextView please refer to this post;
How to detect text view begin editing and end editing in swift 3
I am trying to clear multiple textviews on editing. I know how do so with one textView (IE):
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var myTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
myTextView.delegate = self
}
func textViewDidBeginEditing(textView: UITextView) {
myTextView.text = ""
}
How would I use the same concept for multiple textviews?
func textViewDidBeginEditing(textView: UITextView) {
myTextView.text = ""
}
The above delegate method will get called when a text view begins editing. And this method holds the reference to the textView that called in the textView object. You can use that reference to clear the text instead of using a separate reference/outlet to the textView.
So the method would be:
func textViewDidBeginEditing(textView: UITextView) {
textView.text = ""
}
From the Documentation:
Description:
Tells the delegate that editing began in the specified text field.
This method notifies the delegate that the specified text field just
became the first responder. Use this method to update state
information or perform other tasks. For example, you might use this
method to show overlay views that are visible only while editing.
Implementation of this method by the delegate is optional.
Parameters:
textView
The text view in which an editing session began.
I have an app that has a mix of text fields and text views, and people interact with them in various ways. Some switch from entry field to entry field, some type into the field and hit "done," etc.
Has anyone found a way they particularly like to deal with switching between fields/views, while updating internal data models based on the inputted data as it happens? Any favorite tricks?
Relatedly: if somebody switches from one field to another, what is the order of delegate calls (the should/did begin/end editing) for each field, and how does resignFirstResponder() play into it?
Thanks!
You can set unique tags to each UITextFields and UITextViews to differentiate and store data accordingly for each UITextField or UITextView. Whenever someone interacts with an UITextField, the following delegate methods can be used
func textViewDidBeginEditing(textView: UITextView)
func textFieldDidBeginEditing(textView: UITextField)
The above two delegate functions are called whenever we start editing the UITextField or UITextView. These functions can be used to adjust your layout accordingly so that your UITextField or UITextView doesn't go behind the Keyboard. However, in case of multiple UITextFields and UITextViews in the view, it' better to use a third party library to do this task. I used this https://github.com/michaeltyson/TPKeyboardAvoiding in one of my projects
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
Using the above two functions, you can track the changes made to the text inside the UITextField and UITextView
func textViewDidEndEditing(textView: UITextView)
func textFieldDidEndEditing(textField: UITextField)
The above two functions are called whenever editing ends in a particular UITextView or an UITextField. This can be used for storing data from UITextField or UItextView according to tag.
func textFieldShouldReturn(textField: UITextField) -> Bool
This is called when return key is clicked. You can also use this to store the text typed in this textfield in an array according to tag etc.