التعامل مع الإذن بالوصول إلى طريقة الإدخال

عندما ينتقل تركيز الإدخال داخل حقل نصي قابل للتعديل أو خارجه، يعرض Android الإدخال أو يخفيه، مثل لوحة المفاتيح على الشاشة، حسبما تقتضي الحاجة. يقرّر النظام أيضًا كيفية ظهور واجهة المستخدم وحقل النص أعلى أسلوب الإدخال. على سبيل المثال، عندما تكون المساحة الرأسية على الشاشة محدودة، قد يملأ حقل النص كل المساحة أعلى أسلوب الإدخال.

في معظم التطبيقات، لا تحتاج إلى هذه السلوكيات التلقائية. في بعض الحالات، قد ترغب في مزيد من التحكم في رؤية أسلوب الإدخال وكيفية تأثيره على التخطيط. يشرح هذا الدرس كيفية التحكم في رؤية أسلوب الإدخال والاستجابة له.

إظهار لوحة المفاتيح اللينة عند بدء النشاط

على الرغم من أن Android يركز على أول حقل نصي في التنسيق عند بدء النشاط، إلا أنه لا يعرض لوحة المفاتيح اللينة. هذا السلوك مناسب لأن إدخال النص قد لا يكون المهمة الأساسية في النشاط. ومع ذلك، إذا كان إدخال النص هو المهمة الأساسية فعلاً، كما هو الحال في شاشة تسجيل الدخول، فمن المحتمل أنك تريد أن تظهر لوحة المفاتيح الإلكترونية بشكل تلقائي.

لعرض أسلوب الإدخال عند بدء نشاطك، أضِف السمة android:windowSoftInputMode إلى العنصر <activity> الذي يتضمّن القيمة "stateVisible". مثلاً:

<application ... >
    <activity
        android:windowSoftInputMode="stateVisible" ... >
        ...
    </activity>
   ...
</application>

تحديد كيفية استجابة واجهة المستخدم

عندما تظهر لوحة المفاتيح اللينة على الشاشة، فإنها تقلل من المساحة المتاحة لواجهة مستخدم التطبيق. يقرر النظام كيفية ضبط الجزء المرئي من واجهة المستخدم، لكن قد لا يخطئ بشكل صحيح. لضمان تنفيذ أفضل سلوك لتطبيقك، عليك تحديد طريقة عرض النظام لواجهة المستخدم في المساحة المتبقية.

للإشارة إلى الطريقة المفضّلة لديك في نشاط معيّن، استخدِم السمة android:windowSoftInputMode في العنصر <activity> في البيان مع استخدام إحدى القيمتَين "adjust" (الضبط).

على سبيل المثال، لضمان أنّ النظام يغيّر حجم التنسيق إلى المساحة المتاحة، ما يتيح الوصول إلى كل محتوى التنسيق، حتى إذا كان يتطلّب الانتقال للأسفل، استخدِم "adjustResize":

<application ... >
   <activity
       android:windowSoftInputMode="adjustResize" ... >
       ...
   </activity>
   ...
</application>

يمكنك دمج مواصفات التعديل مع مواصفات الرؤية الأولية للوحة المفاتيح اللينة من القسم السابق:

<activity
    android:windowSoftInputMode="stateVisible|adjustResize" ... >
    ...
</activity>

من المهم تحديد "adjustResize" إذا كانت واجهة المستخدم تتضمّن عناصر تحكّم قد يحتاج المستخدم إلى الوصول إليها مباشرةً بعد إدخال النص أو أثناء إجراء ذلك. على سبيل المثال، إذا كنت تستخدم تنسيقًا نسبيًا لوضع شريط أزرار في أسفل الشاشة، سيؤدي استخدام "adjustResize" إلى تغيير حجم التنسيق بحيث يظهر شريط الأزرار فوق لوحة المفاتيح الإلكترونية.

عرض لوحة المفاتيح الإلكترونية عند الطلب

إذا كانت هناك طريقة في مراحل نشاط نشاطك تريد التأكّد من أن طريقة الإدخال مرئية، يمكنك استخدام InputMethodManager لعرضها.

على سبيل المثال، تستخدم الطريقة التالية View حيث من المتوقع أن يكتب المستخدم شيئًا، ثم تستدعي requestFocus() للتركيز، ثم يستدعي showSoftInput() لفتح أسلوب الإدخال:

Kotlin

fun showSoftKeyboard(view: View) {
   if (view.requestFocus()) {
       val imm = getSystemService(InputMethodManager::class.java)
       imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
   }
}

Java

public void showSoftKeyboard(View view) {
   if (view.requestFocus()) {
       InputMethodManager imm = getSystemService(InputMethodManager.class);
       imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
   }
}

إظهار لوحة المفاتيح اللينة بشكل موثوق

هناك مواقف معيّنة، مثل بدء نشاط معيّن، والتي قد يؤدي فيها استخدام InputMethodManager.showSoftInput() لعرض لوحة المفاتيح الإلكترونية إلى عدم ظهور لوحة المفاتيح البرمجية للمستخدم.

يعتمد إذن الوصول إلى لوحة المفاتيح اللينة عند استخدام showSoftInput() على الشروط التالية:

  • يجب أن تكون طريقة العرض متصلة بلوحة المفاتيح البرمجية. (وبالتالي، يتطلب ذلك تركيز النافذة وطريقة عرض المحرّر لطلب تركيز العرض باستخدام View.requestFocus()).

  • يمكن أن يتأثر مستوى الظهور أيضًا بالسمة android:windowSoftInputMode والعلامات التي تستخدمها showSoftInput().

في حالات استخدام معيّنة، مثل بدء نشاط ما، لا يتم استيفاء بعض هذه الشروط المطلوبة. لا يعتبر النظام أنّ العرض متصل بلوحة المفاتيح البرمجية، ويتجاهل طلب showSoftInput()، ولا تكون لوحة المفاتيح الإلكترونية مرئية للمستخدم.

للتأكد من ظهور لوحة المفاتيح البرمجية بشكل موثوق، يمكنك استخدام البدائل التالية:

  • (يُنصح به) استخدِم WindowInsetsControllerCompat. ويعرض هذا الكائن لوحة المفاتيح اللينة أثناء Activity.onCreate() كما هو موضّح في مقتطف الرمز التالي. يمكن ضمان جدولة المكالمة بعد تركيز النافذة.

Kotlin

editText.requestFocus()
WindowCompat.getInsetsController(window, editText)!!.show(WindowInsetsCompat.Type.ime())

Java

editText.requestFocus();
WindowCompat.getInsetsController(getWindow(), editText).show(WindowInsetsCompat.Type.ime());
  • انشر فيديو قابلاً للركض. يضمن ذلك انتظار تطبيقك إلى أن يتلقّى حدث تركيز النافذة من View.onWindowFocusChanged() قبل طلب الرمز showSoftInput().

Kotlin

class MyEditText : EditText() {
  ...
  override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
    if (hasWindowFocus) {
      requestFocus()
      post {
        val imm: InputMethodManager = getSystemService(InputMethodManager::class.java)
        imm.showSoftInput(this, 0)
      }
    }
  }
}

Java

public class MyEditText extends EditText {
  ...
  @Override
  public void onWindowFocusChanged(boolean hasWindowFocus) {
    if (hasWindowFocus) {
      requestFocus();
      post(() -> {
        InputMethodManager imm = getSystemService(InputMethodManager.class);
        imm.showSoftInput(this, 0);
      });
    }
  }
}

التعامل مع علامات مستوى الرؤية في وقت التشغيل بعناية

عند تغيير إذن الوصول إلى لوحة المفاتيح البسيطة في وقت التشغيل، احرِص على عدم ضبط قيم علامات معيّنة في هذه الطرق. على سبيل المثال، إذا كان التطبيق يتوقّع ظهور لوحة المفاتيح اللينة عند استدعاء View.getWindowInsetsController().show(ime()) في "Activity.onCreate()" أثناء بدء النشاط، يجب أن يحرص مطوِّرو التطبيقات على عدم ضبط علامات SOFT_INPUT_STATE_HIDDEN أو SOFT_INPUT_STATE_ALWAYS_HIDDEN أثناء التشغيل الأولي في حال اختفاء لوحة المفاتيح اللينة بشكل غير متوقع.

يخفي النظام عادةً لوحة المفاتيح اللينة تلقائيًا

في معظم الحالات، ينفّذ النظام عملية إخفاء لوحة المفاتيح اللينة. ويمكن أن يحدث ذلك في أي من الحالات التالية:

  • ينهي المستخدم المهمة في حقل النص.
  • يضغط المستخدم على مفتاح الرجوع أو إيماءات التمرير السريع مع التنقل للخلف.
  • ينتقل المستخدم إلى تطبيق آخر، وهذا التطبيق الآخر قد وضع علامات SOFT_INPUT_STATE_HIDDEN أو SOFT_INPUT_STATE_ALWAYS_HIDDEN عندما يتم التركيز على المشاهدة.

إخفاء لوحة المفاتيح الافتراضية يدويًا استنادًا إلى سلوك النظام السابق

يجب أن يُخفي تطبيقك لوحة المفاتيح اللينة يدويًا في بعض الحالات، مثلاً عندما يفقد حقل النص التركيز في View.OnFocusChangeListener.onFocusChange. استخدِم هذا الأسلوب بحكمة لأنّ إغلاق لوحة المفاتيح الإلكترونية يضر بتجربة المستخدم بشكل غير متوقّع.

إذا كان تطبيقك يخفي لوحة المفاتيح اللينة يدويًا، عليك معرفة ما إذا تم إظهار لوحة المفاتيح الافتراضية بشكل صريح أو ضمنيًا:

  • تُعتبر لوحة المفاتيح الإلكترونية قد تم عرضها بشكل صريح بعد طلب الاتصال بـ showSoftInput().

  • وعلى العكس من ذلك، تُعتبر لوحة المفاتيح اللينة ظاهرة ضمنيًا في أي من الحالات التالية:

    • أظهر النظام لوحة المفاتيح اللينة أثناء تطبيق android:windowSoftInputMode.
    • لقد مرّ تطبيقك SHOW_IMPLICIT إلى showSoftInput().

في العادة، تخفي hideSoftInputFromWindow() لوحة المفاتيح الافتراضية بغض النظر عن كيفية طلبها، ولكن في HIDE_IMPLICIT_ONLY، يمكن الاقتصار على إغلاق لوحة المفاتيح اللينة التي تم طلبها ضمنيًا فقط.

إظهار مربع حوار أو عرض تراكب أعلى لوحة المفاتيح الإلكترونية

في بعض الحالات، قد يحتاج نشاط المحرر إلى إنشاء مربع حوار أو نافذة تراكب غير قابل للتعديل أعلى لوحة المفاتيح اللينة.

يحتوي تطبيقك على بعض الخيارات، والتي تصف الأقسام التالية.

باختصار، احرص على التعامل مع علامات النوافذ للوحة المفاتيح اللينة التي تستهدف النافذة بشكل صحيح بحيث تفي بالتوقعات التالية في ما يتعلق بالترتيب الرأسي (طبقة z):

  • ليست هناك علامات (حالة عادية): خلف طبقة لوحة المفاتيح اللينة، ويمكن استقبال نص.
  • FLAG_NOT_FOCUSABLE : أعلى طبقة لوحة المفاتيح اللينة، ولكن لا يمكن تلقّي نص.
  • FLAG_ALT_FOCUSABLE_IM : أعلى طبقة لوحة المفاتيح اللينة، يمكن التركيز عليها ولكن لا يكون متصلاً بلوحة المفاتيح اللينة. وستحظر أيضًا جميع طرق العرض الموجودة أسفله من الاتصال بلوحة المفاتيح اللينة. هذا مفيد لعرض مربع حوار تطبيق لا يستخدم إدخال النص فوق طبقة لوحة المفاتيح اللينة.
  • FLAG_NOT_FOCUSABLE وFLAG_ALT_FOCUSABLE_IM : خلف طبقة لوحة المفاتيح اللينة، ولكن لا يمكن تلقّي نص.
  • FLAG_NOT_FOCUSABLE وFLAG_NOT_TOUCH_MODAL : فوق لوحة المفاتيح اللينة، واسمح لأحداث اللمس بالمرور "عبر" النافذة على لوحة المفاتيح اللينة.

إنشاء مربع حوار

استخدِم علامة نافذة مربّع الحوار FLAG_ALT_FOCUSABLE_IM لإبقاء مربّع الحوار في أعلى لوحة المفاتيح المصغّرة ومنع لوحة المفاتيح اللينة من التركيز:

Kotlin

val content = TextView(this)
content.text = "Non-editable dialog on top of soft keyboard"
content.gravity = Gravity.CENTER
val builder = AlertDialog.Builder(this)
  .setTitle("Soft keyboard layering demo")
  .setView(content)
mDialog = builder.create()
mDialog!!.window!!
  .addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
mDialog!!.show()

Java

TextView content = new TextView(this);
content.setText("Non-editable dialog on top of soft keyboard");
content.setGravity(Gravity.CENTER);
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
    .setTitle("Soft keyboard layering demo")
    .setView(content);
mDialog = builder.create();
mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
mDialog.show();

إنشاء طريقة عرض مُركّبة

يمكنك إنشاء عرض متراكب يحدد نوع النافذة TYPE_APPLICATION_OVERLAY وعلامة نافذة FLAG_ALT_FOCUSABLE_IM من خلال النشاط الذي يستهدف لوحة المفاتيح الإلكترونية.

Kotlin

val params = WindowManager.LayoutParams(
  width,  /* Overlay window width */
  height,  /* Overlay window height */
  WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */
  WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */
    or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,  /* Allow touch event send to soft keyboard behind the overlay */
  PixelFormat.TRANSLUCENT
)
params.title = "Overlay window"
mOverlayView!!.layoutParams = params
windowManager.addView(mOverlayView, params)

Java

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    width, /* Overlay window width */
    height, /* Overlay window height */
    TYPE_APPLICATION, /* Overlay window type */
    FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */
        | FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */
    PixelFormat.TRANSLUCENT);
params.setTitle("Overlay window");
mOverlayView.setLayoutParams(params);
getWindowManager().addView(mOverlayView, params);

إظهار مربع حوار أو عرض أسفل لوحة المفاتيح اللينة

قد يحتاج تطبيقك إلى إنشاء مربّع حوار أو نافذة تتضمّن السمات التالية:

  • تظهر أسفل لوحة المفاتيح الإلكترونية التي يطلبها نشاط المحرر لعدم تأثرها بإدخال النص.
  • يظل على دراية بالتغييرات التي تطرأ على التغييرات في الحجم الداخلي للوحة المفاتيح اللينة لضبط تخطيط مربع الحوار أو النافذة.

في هذه الحالة، يتوفر لتطبيقك عدة خيارات. توضّح الأقسام التالية هذه الخيارات.

إنشاء مربع حوار

أنشِئ مربّع حوار من خلال ضبط كل من علامة نافذة FLAG_NOT_FOCUSABLE وعلامة نافذة FLAG_ALT_FOCUSABLE_IM:

Kotlin

val content = TextView(this)
content.text = "Non-editable dialog behind soft keyboard"
content.gravity = Gravity.CENTER
val builder = AlertDialog.Builder(this)
  .setTitle("Soft keyboard layering demo")
  .setView(content)
mDialog = builder.create()
mDialog!!.window!!
  .addFlags(FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM)
mDialog!!.show()

Java

TextView content = new TextView(this);
content.setText("Non-editable dialog behind soft keyboard");
content.setGravity(Gravity.CENTER);
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
    .setTitle("Soft keyboard layering demo")
    .setView(content);

mDialog = builder.create();
mDialog.getWindow()
    .addFlags(FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
mDialog.show();

إنشاء طريقة عرض مُركّبة

يمكنك إنشاء عرض يظهر على سطح الفيديو من خلال ضبط كل من علامة نافذة FLAG_NOT_FOCUSABLE وعلامة نافذة FLAG_ALT_FOCUSABLE_IM:

Kotlin

val params = WindowManager.LayoutParams(
  width,  /* Overlay window width */
  height,  /* Overlay window height */
  WindowManager.LayoutParams.TYPE_APPLICATION,  /* Overlay window type */
  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
      or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
  PixelFormat.TRANSLUCENT
)
params.title = "Overlay window"
mOverlayView!!.layoutParams = params
windowManager.addView(mOverlayView, params)

Java

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    width, /* Overlay window width */
    height, /* Overlay window height */
    TYPE_APPLICATION, /* Overlay window type */
    FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM,
    PixelFormat.TRANSLUCENT);
params.setTitle("Overlay window");
mOverlayView.setLayoutParams(params);
getWindowManager().addView(mOverlayView, params);