Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get UITextField cursor change event?

I'm working on Android TV Remote Controller - iOS version

I need to detect cursor change event in UITextField and send this event to Android TV.

I can't find any Delegate or notification will send UITextfield cursor change event.

Is there any way to get this event?

Many thanks.

like image 347
Chao-Yu Avatar asked Oct 30 '22 21:10

Chao-Yu


1 Answers

As far as I know, you can KVO or subclass. Since @NSLeader gave the answer for KVO, I'll explain the latter.

Here is a subclass example:

class MyUITextFieldThatEmitsCursorChangeEvents: UITextField
{
    //Override this, but don't prevent change to its default behavior by 
    //calling the super getter and setter.
    override var selectedTextRange: UITextRange? {
        get {return super.selectedTextRange}
        set {
            self.emitNewlySetCursor(event: newValue) //<- Intercept the value
            super.selectedTextRange = newValue       //Maintain normal behavior
        }
    }
    //I'm going to use a closure to pass the cursor position out, 
    //but you can use a protocol, NotificationCenter, or whatever floats your
    //boat.
    weak var cursorPosnDidChangeEvent: ((Int) -> ())?
    
    //I'm going to abstract the logic here to keep the previous code slim.
    private func emitNewlySetCursor(event range: UITextRange?)
    {
        //Now you have access to the start and end in range.
        //If .start and .end are different, then it means text is highlighted.
        //If you only care about the position where text is about to be 
        //entered, then only worry about .start.
        //This is an example to calculate the cursor position.
        if let rawRangeComponent = range?.start 
        {
            let cursorPosition = offset(from: beginningOfDocument, 
                                        to: rawRangeComponent)

            //Emit the value to whoever cares about it
            self.cursorPosnDidChangeEvent?(cursorPosition) 
        }
    }
}

Then, for example, if we're in a UIViewController:

override func viewDidLoad() 
{
    super.viewDidLoad()
    
    let tf = MyUITextFieldThatEmitsCursorChangeEvents(frame: .zero)
    self.view.addSubview(tf)
    tf.cursorPosnDidChangeEvent = { newCursorPosn in
        print(newCursorPosn) //( ͡° ͜ʖ ͡°)
    }
}
like image 164
Xavier L. Avatar answered Nov 15 '22 07:11

Xavier L.