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

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

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

صفحه‌کلید

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

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

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

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

برای اطلاعات بیشتر، ساختن تمرکز قابل‌ساخت را ببینید.

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

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

برای کنترل رفتار تمرکز، اصلاح‌کننده 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+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 API، رویدادهایی را که ممکن است در گذشته نزدیک رخ داده باشند بررسی کنید:

عدم پذیرش کف دست

وقتی کاربران بااستفاده از قلم طراحی می‌کنند، می‌نویسند، یا با برنامه شما تعامل برقرار می‌کنند، گاهی اوقات با کف دستشان صفحه را لمس می‌کنند. رویداد لمس (روی 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 (میانای برنامه‌سازی کاربردی سطح ۳۲) و نسخه‌های پایین‌تر، تشخیص رد کردن کف دست فقط برای رویدادهای لمس تک‌اشاره‌ای امکان‌پذیر است. اگر لمس کف دست تنها اشاره‌گر باشد، سیستم با تنظیم 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 حاوی یک یا چند مورد با نشانی‌های وب content:// راه‌اندازی می‌شود. برنامه باید یادداشتی ایجاد کند که از اولین تصویر پیوست‌شده به‌عنوان تصویر پس‌زمینه استفاده کند و وارد حالتی شود که کاربر بتواند با قلم روی صفحه نقاشی کند.

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

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

  1. به حالت توسعه‌دهنده بروید و دستگاه را نوشتنی کنید
  2. برای باز کردن ترمینال، Ctrl+Alt+F2 را فشار دهید
  3. اجرای فرمان sudo vi /etc/chrome_dev.conf
  4. برای ویرایش کردن و افزودن --ash-enable-palette به خط جدید در انتهای فایل، i را فشار دهید
  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

  • به‌خاطر داشته باشید که برای دسترسی به مواردی که از خارج برنامه کشیده شده‌اند، با requestDragAndDropPermissions() اجازه درخواست کنید
  • برای اینکه بتوان موردی را به برنامه‌های دیگر کشید، باید پرچم View.DRAG_FLAG_GLOBAL را داشته باشد

    «شروع رویداد کشیدن» را ببینید

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

برنامه‌هایی که مدیریت پیشرفته ورودی موشواره و صفحه لمسی را انجام می‌دهند باید اصلاح‌گر 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" />

منابع بیشتر