การรับและการตั้งค่าตำแหน่งเคอร์เซอร์ของ UITextField และ UITextView ใน Swift


109

ฉันได้ทดลองUITextFieldและวิธีการทำงานกับตำแหน่งเคอร์เซอร์ ฉันพบคำตอบ Objective-C ของความสัมพันธ์จำนวนหนึ่งเช่นเดียวกับใน

แต่เนื่องจากฉันทำงานกับ Swift ฉันจึงต้องการเรียนรู้วิธีรับตำแหน่งเคอร์เซอร์ปัจจุบันและตั้งค่าใน Swift ด้วย

คำตอบด้านล่างเป็นผลมาจากการทดลองและการแปลของฉันจาก Objective-C

คำตอบ:


316

เนื้อหาต่อไปนี้ใช้กับทั้งUITextFieldและUITextView.

ข้อมูลที่เป็นประโยชน์

จุดเริ่มต้นของข้อความในช่องข้อความ:

let startPosition: UITextPosition = textField.beginningOfDocument

ส่วนท้ายสุดของข้อความในช่องข้อความ:

let endPosition: UITextPosition = textField.endOfDocument

ช่วงที่เลือกในปัจจุบัน:

let selectedRange: UITextRange? = textField.selectedTextRange

รับตำแหน่งเคอร์เซอร์

if let selectedRange = textField.selectedTextRange {

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

    print("\(cursorPosition)")
}

กำหนดตำแหน่งเคอร์เซอร์

ในการกำหนดตำแหน่งจริงๆแล้ววิธีการทั้งหมดนี้เป็นการตั้งค่าช่วงที่มีค่าเริ่มต้นและค่าสิ้นสุดเหมือนกัน

ไปยังจุดเริ่มต้น

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

ไปยังจุดสิ้นสุด

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

ไปยังตำแหน่งหนึ่งทางด้านซ้ายของตำแหน่งเคอร์เซอร์ปัจจุบัน

// 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)
    }
}

ไปยังตำแหน่งโดยพลการ

เริ่มต้นที่จุดเริ่มต้นและเลื่อน 5 ตัวอักษรไปทางขวา

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

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

ที่เกี่ยวข้อง

เลือกข้อความทั้งหมด

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

เลือกช่วงของข้อความ

// 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!)
}

แทรกข้อความที่ตำแหน่งเคอร์เซอร์ปัจจุบัน

textField.insertText("Hello")

หมายเหตุ

  • ใช้textField.becomeFirstResponder()เพื่อให้โฟกัสไปที่ช่องข้อความและทำให้แป้นพิมพ์ปรากฏขึ้น

  • ดูคำตอบนี้สำหรับวิธีรับข้อความในบางช่วง

ดูสิ่งนี้ด้วย


จุดประสงค์ของ startPosition คืออะไร? คุณสามารถทำอะไรกับมันได้บ้าง? จุดประสงค์ที่อาจต้องใช้เพื่อให้ได้ตำแหน่งเคอร์เซอร์คืออะไร?
น้ำผึ้ง

2
@ ฮันนี่ฉันใช้ชื่อตัวแปรนั้นเพื่ออ้างถึงสองสิ่งที่แตกต่างกันที่นี่ ประการแรกคือการอ้างถึงจุดเริ่มต้นของฟิลด์ข้อความ มันจะมีประโยชน์ถ้าคุณต้องการย้ายเคอร์เซอร์ไปที่นั่น ประการที่สองคือการอ้างถึงการขอทานจากช่วงของข้อความที่เลือก จะมีประโยชน์หากคุณต้องการคัดลอกช่วงนั้นหรือตั้งค่าแอตทริบิวต์บางอย่าง
Suragch

มีอะไรให้เลื่อนเคอร์เซอร์ไปทางขวาในขณะที่ช่องข้อความว่างเปล่า? ฉันทำตามคำตอบของคุณ แต่ไม่สามารถทำได้
Yucel Bayram

1
@yucelbayram คุณสามารถวางเคอร์เซอร์หลังจาก H textField.endOfDocumentใช้ คุณยังสามารถใช้เครื่องหมายขีดล่างหรือช่องว่างเพื่อแทนตัวอักษรที่ขาดหายไป
Suragch

1
@ArielSD ฉันขอโทษฉันไม่ได้ทำงานนี้มาระยะหนึ่งแล้ว ฉันจำไม่ได้
Suragch

42

ในกรณีของฉันฉันต้องใช้ DispatchQueue:

func textViewDidBeginEditing(_ textView: UITextView) {

   DispatchQueue.main.async{
      textField.selectedTextRange = ...
   }
}

ไม่มีอะไรอื่นจากสิ่งนี้และเธรดอื่น ๆ ที่ใช้งานได้

PS: ฉันตรวจสอบอีกครั้งว่าเธรดใดที่ textViewDidBeginEditing ทำงานอยู่และเป็นเธรดหลักเนื่องจาก UI ทั้งหมดควรทำงานบนดังนั้นจึงไม่แน่ใจว่าเหตุใดความล่าช้าเล็กน้อยที่ใช้ main.asynch จึงทำงานได้


2
ไม่ใช่ความล่าช้า แต่เป็นการวิ่งวนครั้งต่อไป textViewDidBeginEditingส่วนใหญ่มีแนวโน้มช่วงที่เลือกฟิลด์ข้อความที่จะถูกปรับเปลี่ยนโดยฟังก์ชั่นเดียวกับที่เรียกว่า ดังนั้นการวางไว้บนคิวจะเกิดขึ้นหลังจากผู้โทรเสร็จสิ้น
Michael Ozeryansky

@MichaelOzeryansky ใช่ฉันก็คิดอย่างนั้นเหมือนกัน แต่สิ่งนี้ทำให้เกิดคำถาม - อะไรคือวิธีการที่เหมาะสมในการตั้งค่าตำแหน่งเคอร์เซอร์ด้วยตนเอง?
เวลา

ใช้วิธีแก้ปัญหานี้ในกรณีของฉันเช่นกัน
Hattori Hanzō

1

สำหรับการตั้งค่าตำแหน่งเคอร์เซอร์ที่จุดของคุณ:

textView.beginFloatingCursor(at: CGPoint(x: 10.0, y: 10.0))

สำหรับการรีเซ็ตตำแหน่งเคอร์เซอร์:

textView.endFloatingCursor()

หมายเหตุ : ตัวอย่างนี้ใช้ได้ทั้งใน Textview & Textfield


@Suragch Floating Cursor เป็นวิธีการหนึ่งในการตั้งค่าตำแหน่งเคอร์เซอร์ใน textView หรือ textField
Parth Patel

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.