وقتی تمرکز ورودی به داخل یا خارج از فیلد نوشتاری قابلویرایش منتقل میشود، 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() را فرامیخواند تا روش ورودی را باز کند:
کاتلین
fun showSoftKeyboard(view: View) { if (view.requestFocus()) { val imm = getSystemService(InputMethodManager::class.java) imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) } }
جاوا
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()نمایش میدهد، همانطور که در تکهکد زیر نشان داده شده است. تضمین میشود که تماس پساز متمرکز شدن پنجره زمانبندی شود.
کاتلین
editText.requestFocus() WindowCompat.getInsetsController(window, editText)!!.show(WindowInsetsCompat.Type.ime())
جاوا
editText.requestFocus(); WindowCompat.getInsetsController(getWindow(), editText).show(WindowInsetsCompat.Type.ime());
- کد قابلاجرایی پست کنید. این کار تضمین میکند که برنامهتان قبلاز فراخوانی
showSoftInput()، منتظر دریافت رویداد تمرکز پنجره ازView.onWindowFocusChanged()میماند.
کاتلین
class MyEditText : EditText() { ... override fun onWindowFocusChanged(hasWindowFocus: Boolean) { if (hasWindowFocus) { requestFocus() post { val imm: InputMethodManager = getSystemService(InputMethodManager::class.java) imm.showSoftInput(this, 0) } } } }
جاوا
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 استفاده کنید تا کادر گفتگو را بالای صفحهکلید نرمافزاری نگه دارید و از متمرکز شدن صفحهکلید نرمافزاری جلوگیری کنید:
کاتلین
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()
جاوا
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 توسط فعالیت هدف صفحهکلید نرمافزاری.
کاتلین
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)
جاوا
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
، کادر گفتگویی ایجاد کنید:
کاتلین
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()
جاوا
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
، نمای همپوشانی ایجاد کنید:
کاتلین
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)
جاوا
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);