یک روش ورودی ایجاد کنید

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

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

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

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

چرخه حیات IME

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

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

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

اجزای IME را در مانیفست اعلام کنید

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

قطعه کد زیر یک سرویس IME را اعلان می‌کند. این قطعه کد مجوز BIND_INPUT_METHOD را درخواست می‌کند تا سرویس، IME را به سیستم متصل کند، یک فیلتر intent تنظیم می‌کند که با اکشن android.view.InputMethod مطابقت دارد و فراداده (metadata) را برای 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 تعریف می‌کند. این قطعه کد دارای یک فیلتر intent برای 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 به تنظیمات آن دسترسی داشته باشید.

API روش ورودی

کلاس‌های مخصوص 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 را برگردانید. پاسخ null رفتار پیش‌فرض است، بنابراین اگر پیشنهادی ارائه نمی‌دهید، لازم نیست این را پیاده‌سازی کنید.

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

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

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

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

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

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

برای مثال، در اینجا رابطی که Latin IME برای ورودی متن پلتفرم اندروید ارائه می‌دهد، آمده است:

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

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

تصویری که ورودی عددی را در یک 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
یک فیلد متنی برای وارد کردن اعداد. همانطور که در شکل 3 نشان داده شده است، IME لاتین یک صفحه کلید اعداد برای فیلدهایی از این نوع نمایش می‌دهد.
TYPE_CLASS_DATETIME
یک فیلد متنی برای وارد کردن تاریخ و زمان.
TYPE_CLASS_PHONE
یک فیلد متنی برای وارد کردن شماره تلفن‌ها.
TYPE_CLASS_TEXT
یک فیلد متنی برای وارد کردن هر کاراکتر پشتیبانی شده.

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

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

TYPE_TEXT_VARIATION_PASSWORD
نوعی از TYPE_CLASS_TEXT برای وارد کردن رمزهای عبور. متد ورودی به جای متن واقعی، حروف dingbats را نمایش می‌دهد.
TYPE_TEXT_VARIATION_URI
نوعی از TYPE_CLASS_TEXT برای وارد کردن URL های وب و سایر شناسه های منبع یکسان (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 را شناسایی و بین آنها جابجا شود.

با استفاده از عنصر <subtype> ، زیرنوع‌ها را در یکی از فایل‌های منبع XML متد ورودی تعریف کنید. قطعه کد زیر یک 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>

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

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

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

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

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

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

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

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

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

  1. در فایل‌های منبع XML متد ورودی، مقدار supportsSwitchingToNextInputMethod = "true" اعلام کنید. اعلان شما باید مشابه قطعه کد زیر باشد:
    <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. اگر متد مقدار true را برگرداند، یک کلید تغییر نمایش بده.
  4. وقتی کاربر کلید تغییر را فشار می‌دهد، تابع switchToNextInputMethod() را فراخوانی کرده و مقدار false را به آن ارسال می‌کند. مقدار false به سیستم می‌گوید که با همه زیرنوع‌ها، صرف نظر از اینکه به کدام IME تعلق دارند، به طور یکسان رفتار کند. تعیین مقدار true سیستم را ملزم می‌کند که بین زیرنوع‌ها در IME فعلی بچرخد.

ملاحظات عمومی IME

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

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