ایجاد روش ورودی

ویرایشگر روش ورودی (IME) یک کنترل کاربر است که به کاربران اجازه می‌دهد نوشتار وارد کنند. Android چارچوب روش ورودی قابل‌گسترشی ارائه می‌دهد که به برنامه‌ها امکان می‌دهد روش‌های ورودی جایگزین، مانند صفحه‌کلیدهای مجازی یا ورودی گفتار، را به کاربران ارائه دهند. پس‌از نصب IME، کاربر می‌تواند یکی از آن‌ها را از تنظیمات سیستم انتخاب کند و در سراسر سیستم از آن استفاده کند. هربار فقط یک IME می‌تواند فعال باشد.

برای افزودن IME به سیستم Android، برنامه Android حاوی کلاسی ایجاد کنید که InputMethodService را گسترش دهد. علاوه‌براین، معمولاً فعالیتی با عنوان «تنظیمات» ایجاد می‌کنید که گزینه‌ها را به سرویس IME ارسال می‌کند. همچنین می‌توانید واسط کاربر تنظیماتی را تعریف کنید که به‌عنوان بخشی از تنظیمات سیستم نمایش داده می‌شود.

این صفحه موضوعات زیر را پوشش می‌دهد:

اگر با IME کار نکرده‌اید، ابتدا مقاله مقدماتی روش‌های ورودی روی صفحه را بخوانید.

چرخه حیات IME

نمودار زیر چرخه حیات IME را شرح می‌دهد:

تصویری که چرخه زندگی IME را نشان می‌دهد.
شکل ۱. چرخه حیات IME.

بخش‌های زیر نحوه پیاده‌سازی واسط کاربر و کد مرتبط با IME را که از این چرخه حیات پیروی می‌کند شرح می‌دهد.

اعلام مؤلفه‌های IME در مانیفست

در سیستم Android، ‏IME یک برنامه Android است که حاوی سرویس IME ویژه‌ای است. فایل مانیفست برنامه باید سرویس را اعلام کند، اجازه‌های لازم را درخواست کند، فیلتر قصدی ارائه دهد که با کنش action.view.InputMethod مطابقت داشته باشد، و فراداده‌ای ارائه دهد که ویژگی‌های IME را تعریف کند. علاوه‌براین، برای ارائه میانای تنظیماتی که به کاربر اجازه می‌دهد رفتار IME را تغییر دهد، می‌توانید فعالیت «تنظیمات» را تعریف کنید که از «تنظیمات سیستم» قابل‌راه‌اندازی باشد.

قطعه کد زیر یک سرویس IME را اعلام می‌کند. این سرویس اجازه BIND_INPUT_METHOD را درخواست می‌کند تا به سرویس اجازه دهد IME را به سیستم متصل کند، فیلتر قصدی را راه‌اندازی می‌کند که با کنش android.view.InputMethod مطابقت دارد، و فراداده را برای IME تعریف می‌کند:

<!-- Declares the input method service. -->
<service android:name="FastInputIME"
    android:label="@string/fast_input_label"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data android:name="android.view.im"
               android:resource="@xml/method" />
</service>

قطعه بعدی فعالیت تنظیمات را برای IME اعلام می‌کند. این برنامه فیلتر قصدی برای ACTION_MAIN دارد که نشان می‌دهد این فعالیت نقطه ورودی اصلی برای برنامه IME است:

<!-- Optional: an activity for controlling the IME settings. -->
<activity android:name="FastInputIMESettings"
    android:label="@string/fast_input_settings">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>

همچنین می‌توانید دسترسی به تنظیمات IME را مستقیماً از واسط کاربر آن ارائه دهید.

میانای برنامه‌سازی کاربردی روش ورودی

کلاس‌های مختص IME در بسته‌های android.inputmethodservice و android.view.inputmethod یافت می‌شوند. کلاس KeyEvent برای مدیریت نویسه‌های صفحه‌کلید مهم است.

بخش مرکزی IME یک مؤلفه سرویس است—کلاسی که InputMethodService را گسترش می‌دهد. علاوه‌بر پیاده‌سازی چرخه حیات سرویس عادی، این کلاس دارای فراخوان‌های برگشتی برای ارائه واسط کاربر IME، مدیریت ورودی کاربر، و ارائه نوشتار به فیلدی است که تمرکز دارد. به‌طور پیش‌فرض، کلاس InputMethodService بیشتر پیاده‌سازی را برای مدیریت وضعیت و رؤیت‌پذیری IME و برقراری ارتباط با فیلد ورودی فعلی ارائه می‌دهد.

کلاس‌های زیر نیز مهم هستند:

BaseInputConnection
کانال ارتباطی را از InputMethod به برنامه‌ای که ورودی آن را دریافت می‌کند تعریف می‌کند. از آن برای خواندن نوشتار اطراف مکان‌نما، وارد کردن نوشتار در چارگوش نوشتاری، و ارسال رویدادهای کلیدی خام به برنامه استفاده می‌کنید. برنامه‌ها باید این کلاس را گسترش دهند، نه اینکه میانای پایه InputConnection را پیاده‌سازی کنند.
KeyboardView
افزونه‌ای از View که صفحه‌کلید را ارائه می‌کند و به رویدادهای ورودی کاربر پاسخ می‌دهد. جانمایی صفحه‌کلید با نمونه‌ای از Keyboard مشخص می‌شود که می‌توانید آن را در فایل XML تعریف کنید.

طراحی واسط کاربر روش ورودی

دو عنصر دیداری اصلی برای IME وجود دارد: نمای ورودی و نمای نامزدها. فقط باید عناصری را پیاده‌سازی کنید که به روش ورودی‌ای که طراحی می‌کنید مربوط هستند.

نمای ورودی

نمای ورودی همان میانای کاربر است که کاربر در آن نوشتار را به‌صورت کلیک کردن روی کلیدها، دست‌نویس، یا اشاره‌ها وارد می‌کند. وقتی IME برای اولین‌بار نمایش داده می‌شود، سیستم onCreateInputView() فراخوانی برگشتی را فراخوانی می‌کند. در پیاده‌سازی این روش، طرح‌بندی‌ای را که می‌خواهید در پنجره IME نمایش داده شود ایجاد کنید و طرح‌بندی را به سیستم برگردانید. تکه‌کد زیر نمونه‌ای از پیاده‌سازی روش onCreateInputView() را نشان می‌دهد:

کاتلین

override fun onCreateInputView(): View {
    return layoutInflater.inflate(R.layout.input, null).apply {
        if (this is MyKeyboardView) {
            setOnKeyboardActionListener(this@MyInputMethod)
            keyboard = latinKeyboard
        }
    }
}

جاوا

@Override
public View onCreateInputView() {
    MyKeyboardView inputView =
        (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null);

    inputView.setOnKeyboardActionListener(this);
    inputView.setKeyboard(latinKeyboard);

    return inputView;
}

در این مثال، MyKeyboardView نمونه‌ای از پیاده‌سازی سفارشی KeyboardView است که Keyboard را ارائه می‌کند.

نمای نامزدها

نمای گزینه‌ها رابط کاربری‌ای است که IME در آن اصلاحات یا پیشنهادهای احتمالی واژه را برای انتخاب کاربر نمایش می‌دهد. در چرخه حیات IME، سیستم onCreateCandidatesView() را زمانی فراخوانی می‌کند که آماده نمایش نمای نامزدها باشد. در پیاده‌سازی این روش، طرح‌بندی‌ای را برگردانید که پیشنهادهای کلمه را نشان می‌دهد، یا اگر نمی‌خواهید چیزی نشان داده شود، null را برگردانید. پاسخ تهی رفتار پیش‌فرض است، بنابراین اگر پیشنهادی ارائه نمی‌دهید، لازم نیست این را پیاده‌سازی کنید.

ملاحظات طراحی میانای کاربر

این بخش برخی‌از ملاحظات طراحی میانای کاربر را برای IMEها شرح می‌دهد.

مدیریت اندازه‌های مختلف صفحه‌نمایش

میانای کاربر IME شما باید بتواند برای اندازه‌های مختلف صفحه‌نمایش مقیاس‌بندی شود و از هر دو جهت افقی و عمودی پشتیبانی کند. در حالت IME غیرتمام‌صفحه، فضای کافی برای برنامه باقی بگذارید تا فیلد نوشتار و هر بافت مرتبطی را نشان دهد، به‌طوری‌که بیش‌از نیمی از صفحه توسط IME اشغال نشود. در حالت تمام‌صفحه IME، این موضوع مشکلی ایجاد نمی‌کند.

مدیریت انواع مختلف ورودی

فیلدهای نوشتاری Android به شما امکان می‌دهند نوع ورودی خاصی را تنظیم کنید، مانند نوشتار آزاد، اعداد، نشانی‌های وب، نشانی‌های ایمیل، و رشته‌های جستجو. وقتی IME جدیدی را پیاده‌سازی می‌کنید، نوع ورودی هر فیلد را شناسایی کنید و واسط مناسبی برای آن ارائه دهید. بااین‌حال، لازم نیست IME را برای بررسی اینکه کاربر نوشتار معتبری برای نوع ورودی وارد می‌کند یا نه راه‌اندازی کنید. این مسئولیت برعهده برنامه‌ای است که مالک فیلد نوشتاری است.

برای مثال، در اینجا میانایی را می‌بینید که IME لاتین برای ورودی نوشتاری پلاتفرم Android ارائه می‌دهد:

تصویری که ورودی نوشتاری را در IME لاتین نشان می‌دهد
شکل ۲. ورودی نوشتار IME لاتین.

و این واسطی است که IME لاتین برای پلاتفرم Android ارائه می‌دهد ورودی عددی:

تصویری که ورودی عددی را در IME لاتین نشان می‌دهد
شکل ۳. ورودی عددی IME لاتین.

وقتی فیلد ورودی فوکوس دریافت می‌کند و IME شما شروع می‌شود، سیستم onStartInputView() را فرامی‌خواند و یک شیء EditorInfo را ارسال می‌کند که حاوی جزئیاتی درباره نوع ورودی و سایر مشخصه‌های فیلد نوشتاری است. در این شیء، فیلد inputType حاوی نوع ورودی فیلد نوشتار است.

فیلد inputType یک int است که حاوی الگوهای بیتی برای تنظیمات مختلف نوع ورودی است. برای آزمایش آن برای نوع ورودی فیلد نوشتاری، آن را با ثابت TYPE_MASK_CLASS ماسک کنید، به این صورت:

کاتلین

inputType and InputType.TYPE_MASK_CLASS

جاوا

inputType & InputType.TYPE_MASK_CLASS

الگوی بیت نوع ورودی می‌تواند یکی از چندین مقدار باشد، ازجمله:

TYPE_CLASS_NUMBER
فیلد نوشتاری برای وارد کردن اعداد. همان‌طور که در شکل ۳ نشان داده شده است، IME لاتین برای فیلدهای این نوع، صفحه کلید عددی نمایش می‌دهد.
TYPE_CLASS_DATETIME
فیلد نوشتاری برای وارد کردن تاریخ و زمان.
TYPE_CLASS_PHONE
فیلد نوشتاری برای وارد کردن شماره تلفن.
TYPE_CLASS_TEXT
فیلد نوشتاری برای وارد کردن نویسه‌های پشتیبانی‌شده.

این ثابت‌ها با جزئیات بیشتر در سند مرجع InputType شرح داده شده‌اند.

فیلد inputType می‌تواند حاوی بیت‌های دیگری باشد که نشان‌دهنده نوع متغیری از فیلد نوشتاری است، مانند:

TYPE_TEXT_VARIATION_PASSWORD
نوعی از TYPE_CLASS_TEXT برای وارد کردن گذرواژه. روش ورودی به‌جای نوشتار واقعی، نمادهای تزئینی نمایش می‌دهد.
TYPE_TEXT_VARIATION_URI
نوعی از TYPE_CLASS_TEXT برای وارد کردن نشانی‌های وب و دیگر شناسه‌های منبع یکسان (URI).
TYPE_TEXT_FLAG_AUTO_COMPLETE
نوعی از TYPE_CLASS_TEXT برای وارد کردن نوشتاری که برنامه به‌طور خودکار از واژه‌نامه، جستجو، یا امکانات دیگر تکمیل می‌کند.

هنگام آزمایش این گونه‌ها، inputType را با ثابت مناسب بپوشانید. ثابت‌های ماسک دردسترس در سند مرجع InputType فهرست شده است.

ارسال نوشتار به برنامه

وقتی کاربر با IME شما نوشتار وارد می‌کند، می‌توانید با ارسال رویدادهای کلیدی جداگانه یا با ویرایش نوشتار اطراف مکان‌نما در فیلد نوشتار برنامه، نوشتار را به برنامه ارسال کنید. در هر دو مورد، از نمونه‌ای از InputConnection برای ارائه نوشتار استفاده کنید. برای دریافت این نمونه، با InputMethodService.getCurrentInputConnection() تماس بگیرید.

ویرایش کردن نوشتار اطراف مکان‌نما

وقتی ویرایش نوشتار موجود را انجام می‌دهید، برخی‌از روش‌های مفید در BaseInputConnection عبارت‌اند از:

getTextBeforeCursor()
یک CharSequence برمی‌گرداند که حاوی تعداد نویسه‌های درخواست‌شده قبل‌از موقعیت مکان‌نمای فعلی است.
getTextAfterCursor()
یک CharSequence حاوی تعداد نویسه‌های درخواست‌شده پس‌از موقعیت فعلی مکان‌نما برمی‌گرداند.
deleteSurroundingText()
تعداد مشخصی از نویسه‌های قبل و بعداز موقعیت فعلی مکان‌نما را حذف می‌کند.
commitText()
CharSequence را به فیلد نوشتاری ارسال می‌کند و موقعیت جدیدی برای مکان‌نما تنظیم می‌کند.

برای مثال، قطعه کد زیر نشان می‌دهد که چگونه چهار نویسه سمت چپ مکان‌نما را با نوشتار «سلام!» جایگزین کنید:

کاتلین

currentInputConnection.also { ic: InputConnection ->
    ic.deleteSurroundingText(4, 0)
    ic.commitText("Hello", 1)
    ic.commitText("!", 1)
}

جاوا

InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);

پشتیبانی از نوشتن نوشتار قبل‌از اجرا

اگر IME شما نوشتار را پیش‌بینی می‌کند یا برای نوشتن نویسه یا کلمه به چند مرحله نیاز دارد، می‌توانید پیشرفت را در فیلد نوشتار نشان دهید تا زمانی که کاربر کلمه را تأیید کند، و سپس می‌توانید ترکیب‌بندی ناقص را با نوشتار کامل جایگزین کنید. می‌توانید با افزودن span به نوشتار هنگام ارسال آن به setComposingText()، رفتار ویژه‌ای با آن داشته باشید.

قطعه کد زیر نحوه نمایش پیشرفت در فیلد نوشتاری را نشان می‌دهد:

کاتلین

currentInputConnection.also { ic: InputConnection ->
    ic.setComposingText("Composi", 1)
    ic.setComposingText("Composin", 1)
    ic.commitText("Composing ", 1)
}

جاوا

InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);

رهگیری رویدادهای کلید سخت‌افزاری

بااینکه پنجره روش ورودی تمرکز صریح ندارد، رویدادهای کلید سخت‌افزاری را ابتدا دریافت می‌کند و می‌تواند آن‌ها را مصرف کند یا به برنامه بازارسال کند. برای مثال، ممکن است بخواهید از کلیدهای جهت‌دار برای پیمایش در واسط کاربرتان برای انتخاب نامزد درطول ترکیب‌بندی استفاده کنید. همچنین ممکن است بخواهید کلید برگشت را برای بستن هرگونه کادر گفتگوی ناشی از پنجره روش ورودی به‌دام بیندازید.

برای رهگیری کلیدهای سخت‌افزاری، onKeyDown() و onKeyUp() را لغو کنید.

برای کلیدهایی که نمی‌خواهید خودتان رسیدگی کنید، روش super() را فراخوانی کنید.

ایجاد زیرنوع IME

زیرنوع‌ها به IME اجازه می‌دهند چندین حالت ورودی و زبان پشتیبانی‌شده توسط IME را نمایش دهد. زیرنوع می‌تواند نشان‌دهنده موارد زیر باشد:

  • منطقه زبانی، مثل en_US یا fr_FR
  • حالت ورودی، مثل صدا، صفحه‌کلید، یا دست‌نویس
  • سایر سبک‌ها، فرم‌ها، یا ویژگی‌های ورودی مختص IME، مانند جانمایی‌های صفحه‌کلید ۱۰ کلیدی یا QWERTY

حالت می‌تواند هر نوشتاری باشد، مثل «صفحه‌کلید» یا «صدا». زیرنوع می‌تواند ترکیبی از این‌ها را نیز نشان دهد.

اطلاعات زیرنوع برای کادر گفتگوی تعویض IME که از نوار اعلان دردسترس است و برای تنظیمات IME استفاده می‌شود. این اطلاعات همچنین به چارچوب اجازه می‌دهد تا زیرنوع خاصی از IME را مستقیماً بالا بیاورد. وقتی IME می‌سازید، از امکانات زیرنوع استفاده کنید، زیرا به کاربر کمک می‌کند زبان‌ها و حالت‌های مختلف IME را شناسایی کند و بین آن‌ها جابه‌جا شود.

زیرنوع‌ها را در یکی از فایل‌های منبع XML روش ورودی بااستفاده از عنصر <subtype> تعریف کنید. تکه‌کد زیر یک IME را با دو نوع فرعی تعریف می‌کند: یک نوع فرعی صفحه‌کلید برای منطقه زبانی انگلیسی ایالات متحده و یک نوع فرعی صفحه‌کلید دیگر برای منطقه زبانی فرانسوی برای فرانسه:

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
        android:settingsActivity="com.example.softkeyboard.Settings"
        android:icon="@drawable/ime_icon">
    <subtype android:name="@string/display_name_english_keyboard_ime"
            android:icon="@drawable/subtype_icon_english_keyboard_ime"
            android:languageTag="en-US"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="somePrivateOption=true" />
    <subtype android:name="@string/display_name_french_keyboard_ime"
            android:icon="@drawable/subtype_icon_french_keyboard_ime"
            android:languageTag="fr-FR"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="someVariable=30,someInternalOption=false" />
    <subtype android:name="@string/display_name_german_keyboard_ime" ... />
</input-method>

برای اطمینان از اینکه زیرنوع‌هایتان به‌درستی در میانای کاربر برچسب‌گذاری شده‌اند، از `%s` استفاده کنید تا برچسب زیرنوعی دریافت کنید که با برچسب زیرنوع منطقه زبانی یکسان باشد. این موضوع در دو تکه‌کد بعدی نشان داده شده است. اولین تکه‌کد بخشی از فایل XML روش ورودی را نشان می‌دهد:

<subtype
    android:label="@string/label_subtype_generic"
    android:imeSubtypeLocale="en_US"
    android:icon="@drawable/icon_en_us"
    android:imeSubtypeMode="keyboard" />

قطعه بعدی بخشی از فایل strings.xml IME است. منبع رشته label_subtype_generic، که توسط تعریف واسط کاربر روش ورودی برای تنظیم برچسب زیرنوع استفاده می‌شود، به‌صورت زیر تعریف شده است:

<string name="label_subtype_generic">%s</string>

این تنظیم باعث می‌شود نام نمایشی زیرنوع با تنظیمات منطقه مطابقت داشته باشد. برای مثال، در هر منطقه زبانی انگلیسی، نام نمایشی «English (United States)» است.

انتخاب کردن زیرنوع‌های IME از نوار اعلان

سیستم Android همه زیرنوع‌های ارائه‌شده توسط همه IMEها را مدیریت می‌کند. زیرنوع‌های IME به‌عنوان حالت‌های IME که به آن تعلق دارند درنظر گرفته می‌شوند. کاربر می‌تواند از نوار اعلان یا برنامه «تنظیمات» به منوی زیرنوع‌های IME دردسترس پیمایش کند، همان‌طور که در شکل زیر نشان داده شده است:

تصویری که منو سیستم «زبان‌ها و ورودی» را نشان می‌دهد
شکل ۴. منو سیستم زبان‌ها و ورودی.

انتخاب زیرنوع‌های IME از «تنظیمات سیستم»

کاربر همچنین می‌تواند نحوه استفاده از زیرنوع‌ها را در پانل تنظیمات زبان و ورودی در تنظیمات سیستم کنترل کند:

تصویری که منو انتخاب «زبان‌ها» را نشان می‌دهد
شکل ۵. منو سیستم زبان‌ها

جابه‌جایی بین زیرنوع‌های IME

با ارائه کلید جابه‌جایی، مانند نماد زبان کروی‌شکل روی صفحه‌کلید، می‌توانید به کاربران اجازه دهید به‌راحتی بین زیرنوع‌های IME جابه‌جا شوند. این کار کاربردپذیری صفحه‌کلید را بهبود می‌بخشد و برای کاربر راحت است. برای فعال کردن این جابه‌جایی، مراحل زیر را انجام دهید:

  1. supportsSwitchingToNextInputMethod = "true" را در فایل‌های منبع XML روش ورودی اعلام کنید. اعلامیه شما باید شبیه تکه‌کد زیر باشد:
    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
            android:supportsSwitchingToNextInputMethod="true">
  2. روش shouldOfferSwitchingToNextInputMethod() را فراخوانی کنید.
  3. اگر روش مقدار درست را برگرداند، کلید تعویض را نمایش دهید.
  4. وقتی کاربر روی کلید تعویض ضربه می‌زند، switchToNextInputMethod() را فراخوانی کنید و false را ارسال کنید. مقدار نادرست به سیستم می‌گوید که با همه زیرنوع‌ها به‌طور یکسان رفتار کند، صرف‌نظر از اینکه به کدام IME تعلق دارند. مشخص کردن true مستلزم این است که سیستم در IME فعلی بین زیرنوع‌ها بچرخد.

ملاحظات کلی IME

در اینجا موارد دیگری وجود دارد که باید هنگام پیاده‌سازی IME خود در نظر بگیرید:

  • روشی برای کاربران ارائه دهید تا گزینه‌ها را مستقیماً از واسط کاربر IME تنظیم کنند.
  • روشی برای کاربران فراهم کنید تا بتوانند مستقیماً از میانای کاربری روش ورودی به IME دیگری بروند، چون ممکن است چندین IME در دستگاه نصب شده باشد.
  • رابط کاربری IME را به‌سرعت بالا بیاورید. هر منبع بزرگی را پیش‌بارگیری یا به‌صورت درخواستی بارگیری کنید تا کاربران به‌محض ضربه زدن روی فیلد نوشتاری، IME را ببینند. منابع و نماها را برای فراخوانی‌های بعدی روش ورودی ذخیره کنید.
  • بلافاصله پس‌از پنهان شدن پنجره روش ورودی، تخصیص‌های حافظه بزرگ را آزاد کنید تا برنامه‌ها حافظه کافی برای اجرا داشته باشند. اگر IME برای چند ثانیه پنهان شد، از پیام تأخیری برای آزاد کردن منابع استفاده کنید.
  • مطمئن شوید کاربران می‌توانند تا حد امکان نویسه‌های بیشتری برای زبان یا منطقه زبانی مرتبط با IME وارد کنند. کاربران ممکن است از علائم سجاوندی در گذرواژه‌ها یا نام‌های کاربری استفاده کنند، بنابراین IME شما باید نویسه‌های مختلفی را ارائه دهد تا کاربران بتوانند گذرواژه را وارد کنند و به دستگاه دسترسی داشته باشند.