سازگاری ورودی در صفحه نمایش های بزرگ

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

  • پشتیبانی اصلی صفحه‌کلید را آزمایش کنید، مثلاً Ctrl+Z برای واگرد، Ctrl+C برای کپی، و Ctrl+S برای ذخیره. برای مشاهده فهرست میان‌برهای پیش‌فرض صفحه‌کلید، مدیریت کنش‌های صفحه‌کلید را ببینید.
  • پشتیبانی پیشرفته صفحه‌کلید را آزمایش کنید، برای مثال، پیمایش صفحه‌کلید با کلید جهش و کلیدهای جهت‌نما، تأیید ورود نوشتار با کلید ورود، و پخش و مکث با کلید فاصله در برنامه‌های رسانه.
  • تعامل‌های اصلی موشواره را آزمایش کنید، ازجمله کلیک راست برای منوِ زمینه‌ای، تغییر نماد هنگام نگه داشتن نشانگر، و رویدادهای پیمایش با چرخ موشواره یا پد لمسی در مؤلفه‌های سفارشی.
  • دستگاه‌های ورودی مختص برنامه را آزمایش کنید، مانند قلم، کنترل‌کننده‌های بازی، و کنترل‌کننده‌های MIDI برنامه موسیقی.
  • پشتیبانی از ورودی پیشرفته را درنظر بگیرید که می‌تواند برنامه را در محیط‌های رایانه برجسته کند، برای مثال، صفحه لمسی به‌عنوان کراس‌فیدر برای برنامه‌های DJ، ضبط موشواره برای بازی‌ها، و میان‌برهای صفحه‌کلید برای کاربران صفحه‌کلیدمحور.

صفحه‌کلید

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

پیمایش با صفحه‌کلید به‌ندرت در برنامه‌های لمس‌محور پیاده‌سازی می‌شود، اما کاربران هنگام استفاده از برنامه و زمانی که دستشان روی صفحه‌کلید است، انتظار آن را دارند. پیمایش با صفحه‌کلید می‌تواند در تلفن‌ها، رایانه‌های لوحی، دستگاه‌های تاشو، و رایانه‌های رومیزی برای کاربران دارای نیازهای دسترس‌پذیری ضروری باشد.

برای بسیاری از برنامه‌ها، پیمایش با کلیدهای جهت‌نما و کلید جهش به‌طور خودکار توسط چارچوب Android انجام می‌شود. برای مثال، برخی‌از composableها به‌طور پیش‌فرض قابل‌تمرکز هستند، مثل Button یا composable با اصلاح‌گر clickable؛ پیمایش صفحه‌کلید معمولاً باید بدون هیچ کد اضافی کار کند. برای فعال کردن پیمایش صفحه‌کلید برای ترکیب‌پذیرهای سفارشی که به‌طور پیش‌فرض قابل‌تمرکز نیستند، اصلاح‌کننده focusable را اضافه کنید:

var color by remember { mutableStateOf(Green) }
Box(
    Modifier
        .background(color)
        .onFocusChanged { color = if (it.isFocused) Blue else Green }
        .focusable()
) {
    Text("Focusable 1")
}

برای اطلاعات بیشتر، به قابل‌تمرکز کردن یک composable مراجعه کنید.

وقتی کانون فعال باشد، چارچوب Android نگاشت پیمایشی برای همه مؤلفه‌های قابل‌کانون براساس موقعیتشان ایجاد می‌کند. این معمولاً طبق انتظار کار می‌کند و به توسعه بیشتری نیاز نیست.

بااین‌حال، Compose همیشه مورد بعدی صحیح را برای پیمایش زبانه‌ای برای ترکیب‌شدنی‌های پیچیده مانند زبانه‌ها و فهرست‌ها تعیین نمی‌کند، برای مثال، زمانی که یکی از ترکیب‌شدنی‌ها یک پیمایش افقی است که کاملاً قابل‌مشاهده نیست.

برای کنترل رفتار تمرکز، اصلاح‌کننده focusGroup را به ترکیب‌پذیر والد مجموعه‌ای از ترکیب‌پذیرها اضافه کنید. تمرکز به گروه منتقل می‌شود، سپس قبل‌از انتقال به مؤلفه قابل‌تمرکز بعدی، در گروه حرکت می‌کند، برای مثال:

Row {
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col1") }
        Button({}) { Text("Row2 Col1") }
        Button({}) { Text("Row3 Col1") }
    }
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col2") }
        Button({}) { Text("Row2 Col2") }
        Button({}) { Text("Row3 Col2") }
    }
}

برای اطلاعات بیشتر، ارائه ناوبری منسجم با گروه‌های کانونی را ببینید.

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

به‌خاطر داشته باشید که پشتیبانی از صفحه‌کلید ممکن است برای کاربران دارای نیازهای دسترس‌پذیری ضروری باشد.

ضربه‌کلیدها

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

برخی‌از نمونه‌ها عبارتند از برنامه‌های گپ که از کلید Enter برای ارسال پیام استفاده می‌کنند، برنامه‌های رسانه که بازپخش را با کلید فاصله شروع و متوقف می‌کنند، و بازی‌هایی که حرکت را با کلیدهای w،‏ a،‏ s، و d کنترل می‌کنند.

می‌توانید با اصلاح‌کننده onKeyEvent، که یک لامبدا را می‌پذیرد که وقتی مؤلفه اصلاح‌شده رویداد کلیدی دریافت می‌کند فراخوانی می‌شود، ضربه‌های کلید تکی را مدیریت کنید. ویژگی KeyEvent#type به شما امکان می‌دهد تعیین کنید که رویداد فشار دادن کلید (KeyDown) است یا رها کردن کلید (KeyUp):

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    Text("Press S key")
}

یا می‌توانید onKeyUp() را لغو کنید و رفتار موردانتظار را برای هر کد کلید دریافتی اضافه کنید:

kotlin override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }

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

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

میان‌برها

هنگام استفاده از صفحه‌کلید سخت‌افزاری، میان‌برهای صفحه‌کلید رایج که شامل کلیدهای Ctrl،‏ Alt، Shift، و Meta هستند موردانتظار است. اگر برنامه‌ای میان‌برها را پیاده‌سازی نکند، تجربه کاربری می‌تواند برای کاربران ناامیدکننده باشد. کاربران پیشرفته نیز از میان‌برهای مربوط به کارهای خاص برنامه که به‌طور مکرر استفاده می‌شوند استقبال می‌کنند. میان‌برها استفاده از برنامه را آسان‌تر می‌کنند و آن را از برنامه‌هایی که میان‌بر ندارند متمایز می‌کنند.

برخی‌از میان‌برهای رایج عبارتند از Ctrl+S (ذخیره)، Ctrl+Z (واگرد)، و Ctrl+Shift+Z (مجدداً انجام دادن). برای دریافت فهرستی از میان‌برهای پیش‌فرض، مدیریت کنش‌های صفحه‌کلید را ببینید.

شیء KeyEvent دارای مشخصه‌های زیر است که نشان می‌دهد آیا کلیدهای اصلاح‌گر فشار داده شده‌اند یا نه:

برای مثال:

Box(
    Modifier.onKeyEvent {
        if (it.isAltPressed && it.key == Key.A) {
            println("Alt + A is pressed")
            true
        } else {
            false
        }
    }
    .focusable()
)

برای اطلاعات بیشتر، به موارد زیر مراجعه کنید:

قلم

بسیاری از دستگاه‌های دارای صفحه‌نمایش بزرگ با قلم عرضه می‌شوند. برنامه‌های Android قلم را به‌عنوان ورودی صفحه‌لمسی مدیریت می‌کنند. برخی‌از دستگاه‌ها ممکن است میز طراحی USB یا بلوتوث نیز داشته باشند، مثل Wacom Intuos. برنامه‌های Android می‌توانند ورودی بلوتوث دریافت کنند اما ورودی USB را نمی‌توانند دریافت کنند.

برای دسترسی به اشیای قلم MotionEvent، اصلاح‌کننده pointerInteropFilter را به سطح طراحی اضافه کنید. کلاس ViewModel را با روشی پیاده‌سازی کنید که رویدادهای حرکتی را پردازش می‌کند؛ روش را به‌عنوان لامبدا onTouchEvent اصلاح‌کننده pointerInteropFilter ارسال کنید:

@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
   Canvas(modifier = modifier
       .clipToBounds()
       .pointerInteropFilter {
           viewModel.processMotionEvent(it)
       }

   ) {
       // Drawing code here.
   }
}

شیء MotionEvent حاوی اطلاعاتی درباره رویداد است:

امتیازهای تاریخی

Android رویدادهای ورودی را دسته‌بندی می‌کند و آن‌ها را یک‌بار در هر فریم ارائه می‌دهد. قلم می‌تواند رویدادها را با فرکانس‌های بسیار بالاتری نسبت‌به نمایشگر گزارش کند. هنگام ایجاد برنامه‌های طراحی، بااستفاده از میاناهای برنامه‌سازی کاربردی getHistorical، رویدادهایی را که ممکن است در گذشته نزدیک رخ داده باشند بررسی کنید:

رد کردن کف دست

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

Android رویدادهای لمس کف دست را با ارسال MotionEvent لغو می‌کند. اگر برنامه‌تان ACTION_CANCEL را دریافت کرد، اشاره را لغو کنید. اگر برنامه‌تان ACTION_POINTER_UP را دریافت می‌کند، بررسی کنید که FLAG_CANCELED تنظیم شده باشد. اگر این‌طور است، اشاره را لغو کنید.

فقط با FLAG_CANCELED بررسی نکنید. در Android 13 (سطح میانای برنامه‌سازی کاربردی ۳۳) و بالاتر، سیستم FLAG_CANCELED را برای رویدادهای ACTION_CANCEL تنظیم می‌کند، اما سیستم این پرچم را در نسخه‌های پایین‌تر Android تنظیم نمی‌کند.

‫Android نسخه ۱۲

در Android 12 (سطح API‏ ۳۲) و نسخه‌های پایین‌تر، تشخیص رد کردن کف دست فقط برای رویدادهای لمسی تک‌اشاره‌گر امکان‌پذیر است. اگر لمس کف دست تنها اشاره‌گر باشد، سیستم با تنظیم ACTION_CANCEL در شیء رویداد حرکتی، رویداد را لغو می‌کند. اگر اشاره‌گرهای دیگر پایین باشند، سیستم ACTION_POINTER_UP را تنظیم می‌کند که برای تشخیص رد کردن کف دست کافی نیست.

Android 13

در Android 13 (میانای برنامه‌سازی کاربردی سطح ۳۳) و بالاتر، اگر لمس کف دست تنها اشاره‌گر باشد، سیستم با تنظیم ACTION_CANCEL و FLAG_CANCELED روی شیء رویداد حرکتی، رویداد را لغو می‌کند. اگر اشاره‌گرهای دیگر پایین باشند، سیستم ACTION_POINTER_UP و FLAG_CANCELED را تنظیم می‌کند.

هرگاه برنامه‌تان رویداد حرکتی با ACTION_POINTER_UP دریافت کرد، FLAG_CANCELED را بررسی کنید تا مشخص شود آیا رویداد نشان‌دهنده رد کردن کف دست (یا لغو رویداد دیگر) است یا نه.

برنامه‌های یادداشت‌برداری

‫ChromeOS قصد ویژه‌ای دارد که برنامه‌های یادداشت‌برداری ثبت‌شده را به کاربران نشان می‌دهد. برای ثبت برنامه به‌عنوان برنامه یادداشت‌برداری، موارد زیر را به مانیفست برنامه اضافه کنید:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

وقتی برنامه‌ای در سیستم ثبت می‌شود، کاربر می‌تواند آن را به‌عنوان برنامه پیش‌فرض یادداشت‌برداری انتخاب کند. وقتی یادداشت جدیدی درخواست می‌شود، برنامه باید یادداشت خالی‌ای ایجاد کند که برای ورودی قلم آماده باشد. وقتی کاربر می‌خواهد تصویری را حاشیه‌نویسی کند (مثل نماگرفت یا تصویر بارگیری‌شده)، برنامه با ClipData که حاوی یک یا چند مورد با URI content:// است راه‌اندازی می‌شود. برنامه باید یادداشتی ایجاد کند که از اولین تصویر پیوست‌شده به‌عنوان تصویر پس‌زمینه استفاده کند و وارد حالتی شود که کاربر بتواند با قلم روی صفحه بکشد.

آزمایش کردن هدف‌های یادداشت‌برداری بدون قلم نوری

برای آزمایش اینکه آیا برنامه‌ای به‌درستی به هدف‌های یادداشت‌برداری بدون قلم فعال پاسخ می‌دهد یا نه، از روش زیر برای نمایش گزینه‌های یادداشت‌برداری در ChromeOS استفاده کنید:

  1. رفتن به حالت توسعه‌دهنده و قابل‌نوشتن کردن دستگاه
  2. برای باز کردن پایانه، Ctrl+Alt+F2 را فشار دهید
  3. فرمان sudo vi /etc/chrome_dev.conf را اجرا کنید
  4. برای ویرایش کردن، i را فشار دهید و --ash-enable-palette را به خط جدیدی در انتهای فایل اضافه کنید
  5. با فشار دادن Esc و سپس تایپ کردن :، w، q و فشار دادن Enter ذخیره کنید
  6. برای برگشتن به واسط کاربر معمولی ChromeOS، کلیدهای Ctrl+Alt+F1 را فشار دهید
  7. از سیستم خارج شوید، سپس دوباره به سیستم وارد شوید

اکنون منو قلم باید در قفسه باشد:

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

پشتیبانی از موشواره و صفحه لمسی

اکثر برنامه‌ها معمولاً فقط باید سه رویداد متمرکز بر صفحه‌نمایش بزرگ را مدیریت کنند: کلیک راست، نگه داشتن نشانگر، و کشیدن و رها کردن.

کلیک راست

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

برای مدیریت رویدادهای کلیک راست، برنامه‌ها باید View.OnContextClickListener را ثبت کنند:

Box(modifier = Modifier.fillMaxSize()) {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            val rootView = FrameLayout(context)
            val onContextClickListener =
                View.OnContextClickListener { view ->
                    showContextMenu()
                    true
                }
            rootView.setOnContextClickListener(onContextClickListener)
            rootView
        },
    )
}

برای جزئیات مربوط به ساخت منوهای زمینه‌ای، به ایجاد منوِ زمینه‌ای مراجعه کنید.

نگه داشتن موشواره روی یک مورد

با مدیریت رویدادهای نگه داشتن نشانگر می‌توانید چیدمان برنامه‌تان را صیقل‌خورده‌تر و استفاده از آن را آسان‌تر کنید. این امر به‌ویژه برای مؤلفه‌های سفارشی صادق است:

دو نمونه رایج از این مورد عبارت‌اند از:

  • نشان دادن اینکه آیا عنصری رفتار تعاملی دارد یا نه، مثلاً کلیک‌کردنی یا ویرایش‌کردنی بودن، با تغییر دادن نماد اشاره‌گر موشواره
  • افزودن بازخورد دیداری به موارد در فهرست یا جدول بزرگ وقتی اشاره‌گر روی آن‌ها نگه داشته می‌شود

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

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

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

برای افزودن پشتیبانی از کشیدن و رها کردن، به کشیدن و رها کردن مراجعه کنید و پست وبلاگ Android در ChromeOS — پیاده‌سازی کشیدن و رها کردن را ببینید.

ملاحظات ویژه برای ChromeOS

پشتیبانی پیشرفته از اشاره‌گر

برنامه‌هایی که ورودی موشواره و صفحه لمسی را به‌صورت پیشرفته مدیریت می‌کنند باید اصلاح‌کننده pointerInput را برای دریافت PointerEvent پیاده‌سازی کنند:

@Composable
private fun LogPointerEvents(filter: PointerEventType? = null) {
    var log by remember { mutableStateOf("") }
    Column {
        Text(log)
        Box(
            Modifier
                .size(100.dp)
                .background(Color.Red)
                .pointerInput(filter) {
                    awaitPointerEventScope {
                        while (true) {
                            val event = awaitPointerEvent()
                            // handle pointer event
                            if (filter == null || event.type == filter) {
                                log = "${event.type}, ${event.changes.first().position}"
                            }
                        }
                    }
                }
        )
    }
}

شیء PointerEvent را بررسی کنید تا موارد زیر را تعیین کنید:

کنترل‌های بازی

برخی‌از دستگاه‌های Android با صفحه‌نمایش بزرگ از حداکثر چهار کنترل‌کننده بازی پشتیبانی می‌کنند. از میاناهای برنامه‌سازی کاربردی استاندارد دسته کنترل بازی Android برای مدیریت دسته‌های کنترل بازی استفاده کنید (به پشتیبانی از دسته‌های کنترل بازی مراجعه کنید).

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

حالت ترجمه ورودی

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

اگر برنامه‌ای رفتار ورودی سفارشی را پیاده‌سازی کند، برای مثال کنش سفارشی نیشگون گرفتن با دو انگشت روی صفحه لمسی را تعریف کند، یا این ترجمه‌های ورودی رویدادهای ورودی موردانتظار برنامه را ارائه ندهند، می‌توانید با افزودن برچسب زیر به مانیفست Android، حالت ترجمه ورودی را غیرفعال کنید:

<uses-feature
    android:name="android.hardware.type.pc"
    android:required="false" />

منابع بیشتر