لماذا المؤشر في EditText يمثل ألمًا للمبتدئ؟
\nتخيل: أنت تكتب تطبيقًا للملاحظات أو الدردشة. يفتح المستخدم سجلًا موجودًا بالفعل، ويبدأ في الكتابة - وفجأة يُدرج النص الجديد في البداية أو في المنتصف من السطر. موقف مألوف؟ هذه واحدة من تلك المشكلات الصغيرة ولكنها مزعجة للغاية التي يواجهها كل من يبدأ في تعلم تطوير Android باستخدام Kotlin.
\nعلى Stack Overflow، جمع سؤال «Place cursor at the end of text in EditText» آلاف المشاهدات وعشرات الإجابات. لماذا؟ لأنه لا توجد طريقة بديهية «لوضع المؤشر ببساطة في النهاية» في Android SDK. تحتاج إلى معرفة بعض الحيل. اليوم سنشرحها مرة واحدة وإلى الأبد - ببساطة ووضوح مع أمثلة الكود.
\nبالمناسبة، إذا كنت تكتب ليس فقط لتطبيقات Android، ولكن أيضًا، على سبيل المثال، خادمًا خلفيًا بلغة Python - على موقعنا PythonLib ستجد الكثير من المواد للبدء. لكن اليوم نتحدث عن تطوير الأجهزة المحمولة.
\n\nالحل الكلاسيكي: setSelection()
\nالأداة الرئيسية للتحكم في المؤشر في EditText هي طريقة setSelection(). تأخذ فهرس الموضع الذي تريد نقل المؤشر إليه. ولكن لوضع المؤشر في النهاية تمامًا، نحتاج أولاً إلى معرفة طول النص.
// طريقة بسيطة: نأخذ طول النص ونمرره إلى setSelection\neditText.setText("مرحبًا بالعالم!")\neditText.setSelection(editText.text.length)\n\nهذا كل شيء! editText.text.length يُرجع عدد الأحرف. نمرر هذا الرقم إلى setSelection() - ويصبح المؤشر بعد الحرف الأخير.
لكن هناك خدعة: متى نستدعيها؟
\nغالبًا ما يكتب المبتدئون هذا الكود مباشرة بعد setText() - ويتفاجأون بأنه لا يعمل. المشكلة هي أن EditText قد لا يكون قد تم تحديثه بعد. هذا مهم بشكل خاص إذا كنت تقوم بتعيين النص برمجيًا داخل Fragment أو Activity.
الحل الأفضل هو استخدام post() أو مستمع onTextChanged. إليك مثال مع post() - وهذا يضمن تنفيذ الكود بعد أن يصبح العرض (View) جاهزًا:
editText.setText("نص طويل يحتاج إلى التحرير")\neditText.post {\n editText.setSelection(editText.text.length)\n}\n\nالآن سيكون المؤشر بالتأكيد في النهاية. هذه الطريقة هي منقذك في 90% من الحالات.
\n\nماذا لو تغير النص ديناميكيًا؟
\nلنفترض أنك تكتب حقل بحث يقوم تلقائيًا بإدراج الاقتراحات. أو محررًا يمكن للمستخدم فيه إدراج قوالب. في هذه الحالات، تحتاج إلى وضع المؤشر في النهاية في كل مرة يتغير فيها النص برمجيًا.
\nاستخدم TextWatcher أو، بشكل أبسط، فقط استدعِ setSelection() بعد كل تغيير:
fun appendText(newText: String) {\n val currentText = editText.text.toString()\n editText.setText(currentText + newText)\n editText.setSelection(editText.text.length)\n}\n\nهذا الكود يضيف أولاً النص الجديد إلى النص الموجود، ثم ينقل المؤشر إلى النهاية. يعمل بشكل لا تشوبه شائبة.
\n\nخدعة للمتقدمين: Editable و Spannable
\nإذا كنت تعمل مباشرة مع Editable (على سبيل المثال، تحصل عليه من editText.text)، يمكنك استخدام SpannableStringBuilder وطريقة setSpan(). ولكن بالنسبة للمهمة الأساسية «المؤشر في النهاية»، فهذا مبالغ فيه. تذكر: post { setSelection(length) } هو أسلوبك الأساسي.
لماذا لا يعمل هذا في الحوارات (Dialogs) والشظايا (Fragments)؟
\nسؤال شائع آخر على Stack Overflow. إذا كان EditText الخاص بك داخل AlertDialog أو BottomSheetDialogFragment، فقد لا يعمل الكود لأن العرض (View) لم يتم إرفاقه بعد بالنافذة.
الحل هو استخدام onResume() أو onWindowFocusChanged(). في