Uitextfield Starting Cursor Position Is Wrong

UITextField starting cursor position is wrong

You need to always update your UI from the main thread:

DispatchQueue.main.async {
textField.selectedTextRange = textField.textRange(from: textField.endOfDocument, to: textField.endOfDocument)
}

iOS textfield cursor position wrong

This problem raised due to the different character size of the secure dot character and simple character. Dot character are wider in size that's why when you disable secure text entry, character contracts but cursor stays at the same position.

Although this issue should not be in the latest Xcode but I had a same problem in Xcode 6.3.

Explanation:

When you click button to toggle the secureTextEntry, set the becomeFirstResponder again for your textField, it will invoke the keyboard observer and reset the cursor to right position.

    textField?.isSecureTextEntry = !textField.isSecureTextEntry

if textField?.isFirstResponder {
textField?.becomeFirstResponder()
}

Hope this will help you.

c# iOS Can NOT position cursor in UITextField in position 1

Ok, finally got it to work. @Jack Hua's solution won't work for me because I cannot set the textfield as the FirstResponder because there are a number of UIMaskedTextField's on the scrollview, the masked text fields are not the first sub-views on the scrollview, BUT it did give me some ideas! I was beginning to suspect that the initialization of the textfield when the text property was being set was somehow screwing up the cursor position, I believe that is what's happening, just can't prove it as the initialization of the view is happening behind the scenes. BUT I suspect that the setting of the view's mask via the EditMask property made the initialization happen sooner and made it possible to set the cursor position. This also sets the mask from the outset, removing any doubt from the users mind as to what the format of the field is supposed to be. Here's my "final" code:

class UIMaskedTextField : UITextField
{
private string editmask = "";
public String EditMask
{
get => editmask;
set
{
if ((value != ""))
{
editmask = value;
this.Text = editmask.Replace("#", "_"); ;
}
}
}

public UIMaskedTextField()
{
this.Delegate = new PhoneMaskTextViewDelegate(this);
}
}

class PhoneMaskTextViewDelegate : UITextFieldDelegate
{
private UIMaskedTextField MyParent;
int index = 0;
public PhoneMaskTextViewDelegate(UIMaskedTextField parent)
{
MyParent = parent;
}

public override void DidChangeSelection(UITextField textField)
{
// place the cursor in the first fill podition
int y = textField.Text.IndexOf("_");

if (y > -1)
{
var newPosition = textField.GetPosition(textField.BeginningOfDocument, y);
textField.SelectedTextRange = textField.GetTextRange(newPosition, newPosition);
}

}
public override bool ShouldChangeCharacters(UITextField textField, NSRange range, string replacementString)
{
const string maskCharacters = "()-/ ";

string newText = "";
int val;

if (replacementString != "")
{
int fieldlength = 10; // MyParent.EditMask.Length;
string text = textField.Text;
if (text == "")
{
newText = MyParent.EditMask.Replace("#", "_");
}
else
{
newText = text;
}

string totalChar = newText.Replace(" ", "");
totalChar = totalChar.Replace("(", "");
totalChar = totalChar.Replace(")", "");
totalChar = totalChar.Replace("-", "");
totalChar = totalChar.Replace("_", "");

if (Utils.IsNumeric(replacementString))
{
if ((totalChar + replacementString).Length <= fieldlength)
{
if (replacementString != "")
{
index = newText.IndexOf("_");
if (index > -1)
{
StringBuilder sb = new StringBuilder(newText);
char character = char.Parse(replacementString);
sb[index] = character;
newText = sb.ToString();

textField.Text = newText;

// Set cursor to next position
NSRange therange = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location + 1);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
newText = "";
}
}
}
} else
{ // Backspace/Delete pressed

UITextRange position = textField.SelectedTextRange;
string x = position.ToString();
int positionofcursor = Convert.ToInt32(x.Substring(x.IndexOf("(") + 1, x.IndexOf(",") - x.IndexOf("(") - 1));

string characterInPosition = "";

// make sure we're not deleting a mask character
do {
positionofcursor -= 1;
if (positionofcursor > -1)
{
characterInPosition = textField.Text.Substring(positionofcursor, 1);
int j = maskCharacters.IndexOf(characterInPosition);
}else
{
break;
}
} while (maskCharacters.IndexOf(characterInPosition) > -1);

if (positionofcursor > -1)
{
StringBuilder sb = new StringBuilder(textField.Text);
sb[positionofcursor] = char.Parse("_");
textField.Text = sb.ToString();

NSRange therange = new NSRange(positionofcursor, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, therange.Location);
UITextPosition end = textField.GetPosition(start, therange.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
}

return Int32.TryParse(newText, out val);
}
}

Getting and Setting Cursor Position of UITextField and UITextView in Swift

The following content applies to both UITextField and UITextView.

Useful information

The very beginning of the text field text:

let startPosition: UITextPosition = textField.beginningOfDocument

The very end of the text field text:

let endPosition: UITextPosition = textField.endOfDocument

The currently selected range:

let selectedRange: UITextRange? = textField.selectedTextRange

Get cursor position

if let selectedRange = textField.selectedTextRange {

let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)

print("\(cursorPosition)")
}

Set cursor position

In order to set the position, all of these methods are actually setting a range with the same start and end values.

To the beginning

let newPosition = textField.beginningOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)

To the end

let newPosition = textField.endOfDocument
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)

To one position to the left of the current cursor position

// only if there is a currently selected range
if let selectedRange = textField.selectedTextRange {

// and only if the new position is valid
if let newPosition = textField.position(from: selectedRange.start, offset: -1) {

// set the new position
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
}

To an arbitrary position

Start at the beginning and move 5 characters to the right.

let arbitraryValue: Int = 5
if let newPosition = textField.position(from: textField.beginningOfDocument, offset: arbitraryValue) {

textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}

Related

Select all text

textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)

Select a range of text

// Range: 3 to 7
let startPosition = textField.position(from: textField.beginningOfDocument, offset: 3)
let endPosition = textField.position(from: textField.beginningOfDocument, offset: 7)

if startPosition != nil && endPosition != nil {
textField.selectedTextRange = textField.textRange(from: startPosition!, to: endPosition!)
}

Insert text at the current cursor position

textField.insertText("Hello")

Notes

  • Use textField.becomeFirstResponder() to give focus to the text field and make the keyboard appear.

  • See this answer for how to get the text at some range.

See also

  • How to Create a Range in Swift

iOS Added programmatically UITextField does not scroll text to cursor position while editing

My particular issue was resolved by increasing height size from 20 to 25. Most probably it happened because iOS was not able to adjust text because of font size and textfield height.

let itemNameTextField = UITextField(frame: CGRect(x: 20, y: 40, width: textFieldWidth, height: 25))

In iOS, Cursor position is not able to update from the Started event using the SelectedTextRange

Its necessary to queue the change so that it occurs after Started event returns:

CoreFoundation.DispatchQueue.MainQueue.DispatchAsync( () => {
this.SelectedTextRange = this.GetTextRange(positionToSet, positionToSet);
});

Based on Leo Dabus' answer in swift.

Tested on iOS simulator, iPhone 11, iOS 15.0.



Related Topics



Leave a reply



Submit