ویژگی های پیشرفته قلم

‫Android و ChromeOS انواع مختلفی از میاناهای برنامه‌سازی کاربردی را ارائه می‌دهند تا به شما کمک کنند برنامه‌هایی بسازید که تجربه استثنایی استفاده از قلم را به کاربران ارائه می‌دهند. کلاس MotionEvent اطلاعات مربوط به تعامل قلم با صفحه را نشان می‌دهد، ازجمله فشار قلم، جهت، کج کردن، نگه داشتن، و تشخیص کف دست. کتابخانه‌های پیش‌بینی حرکت و گرافیک با تأخیر کم، رندرینگ قلم روی صفحه را بهبود می‌بخشند تا تجربه‌ای طبیعی مانند قلم و کاغذ ارائه دهند.

MotionEvent

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

داده‌های رویداد

برای دسترسی به اشیای قلم 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 داده‌های مربوط به جنبه‌های زیر از رویداد واسط کاربر را ارائه می‌دهد:

  • کنش‌ها: تعامل فیزیکی با دستگاه—لمس کردن صفحه، حرکت دادن اشاره‌گر روی سطح صفحه، نگه داشتن اشاره‌گر روی سطح صفحه
  • اشاره‌گرها: شناسه‌های اشیایی که با صفحه تعامل دارند—انگشت، قلم، موشواره
  • محور: نوع داده—مختصات x و y، فشار، کج کردن، جهت، و نگه داشتن (فاصله)

کنش‌ها

برای پیاده‌سازی پشتیبانی از قلم، باید بدانید کاربر چه کنشی را انجام می‌دهد.

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

کنش شرح
ACTION_DOWN
ACTION_POINTER_DOWN
اشاره‌گر با صفحه تماس برقرار کرده است.
ACTION_MOVE اشاره‌گر در صفحه حرکت می‌کند.
ACTION_UP
ACTION_POINTER_UP
اشاره‌گر دیگر با صفحه‌نمایش در تماس نیست
ACTION_CANCEL وقتی مجموعه حرکت قبلی یا فعلی باید لغو شود.

برنامه شما می‌تواند کارهایی مثل شروع کردن خط جدید هنگام رخ دادن ACTION_DOWN، کشیدن خط با ACTION_MOVE,، و تمام کردن خط هنگام راه‌اندازی شدن ACTION_UP را انجام دهد.

مجموعه کنش‌های MotionEvent از ACTION_DOWN تا ACTION_UP برای یک اشاره‌گر مشخص، مجموعه حرکتی نامیده می‌شود.

اشاره‌گرها

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

محدوده نمایه‌های اشاره‌گر از صفر تا تعداد اشاره‌گرهای برگردانده‌شده توسط MotionEvent#pointerCount() منهای ۱ است.

مقادیر محور اشاره‌گرها را می‌توان با روش getAxisValue(axis, pointerIndex) دریافت کرد. وقتی نمایه اشاره‌گر حذف شود، سیستم مقدار اولین اشاره‌گر، یعنی اشاره‌گر صفر (۰)، را برمی‌گرداند.

اشیاء MotionEvent حاوی اطلاعاتی درباره نوع اشاره‌گر مورداستفاده هستند. می‌توانید نوع اشاره‌گر را با تکرار کردن در نمایه‌های اشاره‌گر و فراخوانی روش getToolType(pointerIndex) دریافت کنید.

برای آشنایی بیشتر با اشاره‌گرها، مدیریت اشاره‌های چندلمسی را ببینید.

ورودی‌های قلم

می‌توانید ورودی‌های قلم را با TOOL_TYPE_STYLUS فیلتر کنید:

val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)

قلم همچنین می‌تواند گزارش دهد که به‌عنوان پاک‌کن با TOOL_TYPE_ERASER استفاده می‌شود:

val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)

داده‌های محور قلم

ACTION_DOWN و ACTION_MOVE داده‌های محور را درباره قلم ارائه می‌دهند، یعنی مختصات x و y، فشار، جهت، کج کردن، و نگه داشتن.

برای فعال کردن دسترسی به این داده‌ها، MotionEvent API getAxisValue(int) را ارائه می‌دهد، که در آن پارامتر یکی از شناسه‌های محور زیر است:

Axis برگرداندن مقدار getAxisValue()
AXIS_X مختصات X رویداد حرکتی.
AXIS_Y مختصات Y رویداد حرکتی.
AXIS_PRESSURE برای صفحه لمسی یا پد لمسی، فشاری که توسط انگشت، قلم، یا اشاره‌گر دیگر اعمال می‌شود. برای موشواره یا گوی پیمایش، اگر دکمه اصلی فشار داده شود، ۱ و درغیراین‌صورت، ۰.
AXIS_ORIENTATION برای صفحه لمسی یا صفحه لمسی، جهت انگشت، قلم، یا اشاره‌گر دیگر نسبت به صفحه عمودی دستگاه.
AXIS_TILT زاویه شیب قلم برحسب رادیان.
AXIS_DISTANCE فاصله قلم از صفحه.

برای مثال، MotionEvent.getAxisValue(AXIS_X) مختصات x را برای نشانگر اول برمی‌گرداند.

همچنین به مدیریت اشاره‌های چندلمسی مراجعه کنید.

موقعیت

می‌توانید مختصات x و y اشاره‌گر را با فراخوانی‌های زیر بازیابی کنید:

قلم لمسی درحال کشیدن روی صفحه‌نمایش با مختصات x و y نگاشت‌شده.
شکل ۱. مختصات x و y صفحه‌نمایش برای اشاره‌گر قلم.

فشار

می‌توانید فشار اشاره‌گر را با MotionEvent#getAxisValue(AXIS_PRESSURE) یا، برای اشاره‌گر اول، MotionEvent#getPressure() بازیابی کنید.

مقدار فشار برای صفحه‌های لمسی یا صفحه‌های لمسی مقداری بین ۰ (بدون فشار) و ۱ است، اما بسته به کالیبراسیون صفحه، مقادیر بالاتری نیز می‌تواند برگردانده شود.

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

جهت‌‌

جهت نشان می‌دهد که قلم به‌سمت کدام جهت است.

جهت اشاره‌گر را می‌توان بااستفاده از getAxisValue(AXIS_ORIENTATION) یا getOrientation() (برای اشاره‌گر اول) بازیابی کرد.

برای قلم، جهت به‌عنوان مقدار رادیان بین ۰ تا pi (𝛑) در جهت عقربه‌های ساعت یا ۰ تا pi- در خلاف جهت عقربه‌های ساعت برگردانده می‌شود.

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

شکل ۳. قلم به‌سمت چپ با زاویه حدود منفی ۰٫۵۷ رادیان اشاره می‌کند.

شیب

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

«شیب» زاویه مثبت قلم را برحسب رادیان برمی‌گرداند، که در آن صفر عمود بر صفحه‌نمایش است و 𝛑/۲ روی سطح صاف است.

زاویه کجی را می‌توان بااستفاده از getAxisValue(AXIS_TILT) بازیابی کرد (میان‌بری برای نشانگر اول وجود ندارد).

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

قلم با زاویه حدود ۴۰ درجه نسبت به سطح صفحه‌نمایش کج شده است.
شکل ۴. قلم با زاویه حدود ۰٫۷۸۵ رادیان یا ۴۵ درجه نسبت‌به خط عمود کج شده است.

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

فاصله قلم از صفحه را می‌توان با getAxisValue(AXIS_DISTANCE) به‌دست آورد. این روش مقداری از ۰٫۰ (تماس با صفحه) تا مقادیر بالاتر را با دور شدن قلم از صفحه برمی‌گرداند. فاصله شناور بین صفحه‌نمایش و نوک قلم به سازنده صفحه‌نمایش و قلم بستگی دارد. ازآنجایی‌که پیاده‌سازی‌ها می‌توانند متفاوت باشند، برای عملکردهای حیاتی برنامه به مقادیر دقیق تکیه نکنید.

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

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

توجه: Compose اصلاح‌گرهایی ارائه می‌دهد که بر حالت تعاملی عناصر میانای کاربر تأثیر می‌گذارند:

  • hoverable: پیکربندی مؤلفه برای شناور شدن بااستفاده از رویدادهای ورود و خروج اشاره‌گر.
  • indication: جلوه‌های دیداری را برای این مؤلفه هنگام وقوع تعاملات ترسیم می‌کند.

رد کردن لمس کف دست، پیمایش، و ورودی‌های ناخواسته

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

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

ACTION_CANCEL و FLAG_CANCELED

ACTION_CANCEL و FLAG_CANCELED هر دو طراحی شده‌اند تا به شما اطلاع دهند که مجموعه MotionEvent قبلی باید از آخرین ACTION_DOWN لغو شود، بنابراین می‌توانید، برای مثال، آخرین حرکت قلم را برای برنامه طراحی برای اشاره‌گر داده‌شده واگرد کنید.

ACTION_CANCEL

در Android 1.0 (سطح میانای برنامه‌سازی کاربردی ۱) اضافه شد

ACTION_CANCEL نشان می‌دهد که مجموعه قبلی رویدادهای حرکتی باید لغو شود.

‫ACTION_CANCEL زمانی فعال می‌شود که هریک از موارد زیر شناسایی شود:

  • اشاره‌های پیمایش
  • رد کردن کف دست

وقتی ACTION_CANCEL راه‌اندازی شد، باید اشاره‌گر فعال را با getPointerId(getActionIndex()) شناسایی کنید. سپس خط ایجادشده با آن اشاره‌گر را از سابقه ورودی بردارید و صحنه را دوباره رندر کنید.

FLAG_CANCELED

در Android 13 (سطح میانای برنامه‌سازی کاربردی ۳۳) اضافه شده است

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

به‌صورت زیر به مقدار پرچم دسترسی پیدا می‌کنید:

val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED

اگر پرچم تنظیم شده است، باید آخرین مجموعه MotionEvent را از آخرین ACTION_DOWN از این اشاره‌گر واگرد کنید.

مانند ACTION_CANCEL، اشاره‌گر را می‌توان با getPointerId(actionIndex) پیدا کرد.

شکل ۶. ضربه قلم و لمس کف دست MotionEvent مجموعه ایجاد می‌کند. لمس کف دست لغو شد و نمایشگر دوباره رندر شد.

تمام‌صفحه، لبه‌تالبه، و اشاره‌های پیمایش

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

شکل ۷. اشاره تند کشیدن برای انتقال برنامه به پس‌زمینه.

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

همچنین بخش رد کردن لمس کف دست، پیمایش، و ورودی‌های ناخواسته را ببینید.

برای جلوگیری از ایجاد رویدادهای لمسی ناخواسته توسط اشاره‌های پیمایش، از روش setSystemBarsBehavior() و BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE WindowInsetsController استفاده کنید:

// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

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

تأخیر پایین

تأخیر زمانی است که سخت‌افزار، سیستم، و برنامه برای پردازش و ارائه ورودی کاربر نیاز دارند.

تأخیر = پردازش ورودی سخت‌افزار و سیستم‌عامل + پردازش برنامه + ترکیب‌بندی سیستم

  • پرداز زدن سخت‌افزاری
تأخیر باعث می‌شود که خط رندرشده از موقعیت قلم عقب بماند. فاصله بین خط ترسیم‌شده و موقعیت قلم نشان‌دهنده تأخیر است.
شکل ۸. تأخیر باعث می‌شود که خط رندرشده از موقعیت قلم عقب بماند.

منبع تأخیر

  • ثبت قلم با صفحه لمسی (سخت‌افزار): اتصال بی‌سیم اولیه وقتی قلم و سیستم‌عامل برای ثبت و همگام‌سازی با یکدیگر ارتباط برقرار می‌کنند.
  • نرخ نمونه‌برداری لمسی (سخت‌افزار): تعداد دفعاتی در ثانیه که صفحه لمسی بررسی می‌کند آیا اشاره‌گر سطح را لمس می‌کند یا نه، از ۶۰ تا ۱۰۰۰ هرتز.
  • پردازش ورودی (برنامه): اعمال رنگ، جلوه‌های گرافیکی، و تبدیل روی ورودی کاربر.
  • پرداخت گرافیکی (سیستم‌عامل + سخت‌افزار): تعویض میان‌گیر، پردازش سخت‌افزاری.

گرافیک با تأخیر کم

کتابخانه گرافیک با تأخیر کم Jetpack زمان پردازش بین ورودی کاربر و بازپرداخت روی صفحه را کاهش می‌دهد.

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

پرداز کردن میان‌گیر جلو

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

برنامه در میانگیر صفحه می‌نویسد و از میانگیر صفحه می‌خواند.
شکل ۹. پرداز کردن میان‌گیر جلو.
برنامه در چندمیان‌گیر می‌نویسد که با میان‌گیر صفحه جابه‌جا می‌شود. برنامه از بافر صفحه می‌خواند.
شکل ۱۰. پرداز چندمیان‌گیری.

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

کتابخانه با تأخیر کم از Android 10 (سطح API‏ ۲۹) و بالاتر و در دستگاه‌های ChromeOS با Android 10 (سطح API‏ ۲۹) و بالاتر دردسترس است.

وابستگی‌ها

کتابخانه با تأخیر کم مؤلفه‌هایی را برای پیاده‌سازی رندر میان‌گیر جلو ارائه می‌دهد. کتابخانه به‌عنوان وابستگی در فایل build.gradle ماژول برنامه اضافه شده است:

dependencies {
    implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}

پاسخ‌های تماس GLFrontBufferRenderer

کتابخانه با تأخیر کم شامل میانای GLFrontBufferRenderer.Callback است که روش‌های زیر را تعریف می‌کند:

کتابخانه با تأخیر کم درباره نوع داده‌ای که با GLFrontBufferRenderer استفاده می‌کنید نظری ندارد.

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

بازخوانی‌ها

برای فعال کردن بازخوانی‌های پردازشی، GLFrontBufferedRenderer.Callback را اجرا کنید و onDrawFrontBufferedLayer() و onDrawDoubleBufferedLayer() را لغو کنید. GLFrontBufferedRenderer از فراخوانی‌های برگشتی برای ارائه داده‌های شما به بهینه‌ترین شکل ممکن استفاده می‌کند.

val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {
   override fun onDrawFrontBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       param: DATA_TYPE
   ) {
       // OpenGL for front buffer, short, affecting small area of the screen.
   }
   override fun onDrawMultiDoubleBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       params: Collection<DATA_TYPE>
   ) {
       // OpenGL full scene rendering.
   }
}
یک نمونه از GLFrontBufferedRenderer را اعلام کنید

GLFrontBufferedRenderer را با ارائه SurfaceView و برگشت‌های تماسی که قبلاً ایجاد کرده‌اید آماده کنید. GLFrontBufferedRenderer بااستفاده از فراخوان‌های برگشتی شما، پرداخت را برای میان‌گیر جلو و دوگانه بهینه می‌کند:

var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
درحال پرداز زدن

وقتی روش renderFrontBufferedLayer() را فراخوانی می‌کنید، رندر کردن میان‌گیر جلو شروع می‌شود و این کار باعث راه‌اندازی فراخوانی onDrawFrontBufferedLayer() می‌شود.

وقتی تابع commit() را فراخوانی می‌کنید، پرداز با میان‌گیر دوگانه ازسر گرفته می‌شود و این کار باعث راه‌اندازی فراخوان برگشتی onDrawMultiDoubleBufferedLayer() می‌شود.

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

می‌توانید از requestUnbufferedDispatch() استفاده کنید تا درخواست کنید سیستم ورودی رویدادهای حرکتی را دسته‌بندی نکند، بلکه آن‌ها را به‌محض دردسترس قرار گرفتن ارائه دهد:

when (motionEvent.action) {
   MotionEvent.ACTION_DOWN -> {
       // Deliver input events as soon as they arrive.
       view.requestUnbufferedDispatch(motionEvent)
       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_MOVE -> {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_UP -> {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit()
   }
   MotionEvent.CANCEL -> {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel()
   }
}

بایدها و نبایدهای پرداز زدن

✓ موارد مجاز

بخش‌های کوچکی از صفحه‌نمایش، دست‌نویسی، نقاشی، طراحی.

✗ نبایدها

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

پارگی

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

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

پیش‌بینی حرکت

کتابخانه پیش‌بینی حرکت Jetpack با تخمین زدن مسیر ضربه کاربر و ارائه نقاط مصنوعی موقت به رندرکننده، تأخیر درک‌شده را کاهش می‌دهد.

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

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

کتابخانه پیش‌بینی حرکت از Android 4.4 (سطح API‏ ۱۹) و بالاتر و در دستگاه‌های ChromeOS دارای Android 9 (سطح API‏ ۲۸) و بالاتر دردسترس است.

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

وابستگی‌ها

کتابخانه پیش‌بینی حرکت، پیاده‌سازی پیش‌بینی را ارائه می‌دهد. کتابخانه به‌عنوان وابستگی در فایل build.gradle ماژول برنامه اضافه شده است:

dependencies {
    implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}

پیاده‌سازی

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

  • record(): MotionEvent شیء را به‌عنوان سابقه‌ای از کنش‌های کاربر ذخیره می‌کند
  • predict(): MotionEvent پیش‌بینی‌شده را برمی‌گرداند
نمونه‌ای از MotionEventPredictor را اعلام کنید
var motionEventPredictor = MotionEventPredictor.newInstance(view)
تغذیه پیش‌بینی‌کننده با داده‌ها
motionEventPredictor.record(motionEvent)
پیش‌بینی کردن

when (motionEvent.action) {
   MotionEvent.ACTION_MOVE -> {
       val predictedMotionEvent = motionEventPredictor?.predict()
       if(predictedMotionEvent != null) {
            // use predicted MotionEvent to inject a new artificial point
       }
   }
}

بایدها و نبایدهای پیش‌بینی حرکت

✓ موارد مجاز

وقتی نقطه پیش‌بینی‌شده جدیدی اضافه می‌شود، نقاط پیش‌بینی را بردارید.

✗ نبایدها

از نقاط پیش‌بینی برای پرداخت نهایی استفاده نکنید.

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

ChromeOS به برنامه شما امکان می‌دهد برخی‌از کنش‌های یادداشت‌برداری را اعلام کند.

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

برای ثبت برنامه به‌عنوان برنامه یادداشت‌برداری در Android، به ایجاد برنامه یادداشت‌برداری مراجعه کنید.

Android 14 (سطح میانای برنامه‌سازی کاربردی ۳۴) ACTION_CREATE_NOTE را معرفی کرد که به برنامه شما امکان می‌دهد فعالیت یادداشت‌برداری را در صفحه قفل شروع کند.

تشخیص جوهر دیجیتال با ML Kit

با تشخیص جوهر دیجیتال ML Kit، برنامه شما می‌تواند نوشتار دست‌نویس را روی سطح دیجیتال به صدها زبان تشخیص دهد. همچنین می‌توانید طرح‌ها را طبقه‌بندی کنید.

«کیت یادگیری ماشین» کلاس Ink.Stroke.Builder را برای ایجاد اشیاء Ink ارائه می‌دهد که می‌توانند توسط مدل‌های یادگیری ماشین پردازش شوند تا دست‌نوشته را به نوشتار تبدیل کنند.

علاوه‌بر تشخیص دست‌نویس، این مدل می‌تواند اشاره‌ها مثل حذف و دایره کشیدن را تشخیص دهد.

برای کسب اطلاعات بیشتر، به تشخیص جوهر دیجیتال مراجعه کنید.

منابع بیشتر

راهنمای توسعه‌دهندگان

Codelabs

،

‫Android و ChromeOS انواع مختلفی از میاناهای برنامه‌سازی کاربردی را ارائه می‌دهند تا به شما کمک کنند برنامه‌هایی بسازید که تجربه استثنایی استفاده از قلم را به کاربران ارائه می‌دهند. کلاس MotionEvent اطلاعات مربوط به تعامل قلم با صفحه را نشان می‌دهد، ازجمله فشار قلم، جهت، کج کردن، نگه داشتن، و تشخیص کف دست. کتابخانه‌های پیش‌بینی حرکت و گرافیک با تأخیر کم، رندرینگ قلم روی صفحه را بهبود می‌بخشند تا تجربه‌ای طبیعی مانند قلم و کاغذ ارائه دهند.

MotionEvent

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

داده‌های رویداد

برای دسترسی به اشیای قلم 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 داده‌های مربوط به جنبه‌های زیر از رویداد واسط کاربر را ارائه می‌دهد:

  • کنش‌ها: تعامل فیزیکی با دستگاه—لمس کردن صفحه، حرکت دادن اشاره‌گر روی سطح صفحه، نگه داشتن اشاره‌گر روی سطح صفحه
  • اشاره‌گرها: شناسه‌های اشیایی که با صفحه تعامل دارند—انگشت، قلم، موشواره
  • محور: نوع داده—مختصات x و y، فشار، کج کردن، جهت، و نگه داشتن (فاصله)

کنش‌ها

برای پیاده‌سازی پشتیبانی از قلم، باید بدانید کاربر چه کنشی را انجام می‌دهد.

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

کنش شرح
ACTION_DOWN
ACTION_POINTER_DOWN
اشاره‌گر با صفحه تماس برقرار کرده است.
ACTION_MOVE اشاره‌گر در صفحه حرکت می‌کند.
ACTION_UP
ACTION_POINTER_UP
اشاره‌گر دیگر با صفحه‌نمایش در تماس نیست
ACTION_CANCEL وقتی مجموعه حرکت قبلی یا فعلی باید لغو شود.

برنامه شما می‌تواند کارهایی مثل شروع کردن خط جدید هنگام رخ دادن ACTION_DOWN، کشیدن خط با ACTION_MOVE,، و تمام کردن خط هنگام راه‌اندازی شدن ACTION_UP را انجام دهد.

مجموعه کنش‌های MotionEvent از ACTION_DOWN تا ACTION_UP برای یک اشاره‌گر مشخص، مجموعه حرکتی نامیده می‌شود.

اشاره‌گرها

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

محدوده نمایه‌های اشاره‌گر از صفر تا تعداد اشاره‌گرهای برگردانده‌شده توسط MotionEvent#pointerCount() منهای ۱ است.

مقادیر محور اشاره‌گرها را می‌توان با روش getAxisValue(axis, pointerIndex) دریافت کرد. وقتی نمایه اشاره‌گر حذف شود، سیستم مقدار اولین اشاره‌گر، یعنی اشاره‌گر صفر (۰)، را برمی‌گرداند.

اشیاء MotionEvent حاوی اطلاعاتی درباره نوع اشاره‌گر مورداستفاده هستند. می‌توانید نوع اشاره‌گر را با تکرار کردن در نمایه‌های اشاره‌گر و فراخوانی روش getToolType(pointerIndex) دریافت کنید.

برای آشنایی بیشتر با اشاره‌گرها، مدیریت اشاره‌های چندلمسی را ببینید.

ورودی‌های قلم

می‌توانید ورودی‌های قلم را با TOOL_TYPE_STYLUS فیلتر کنید:

val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)

قلم همچنین می‌تواند گزارش دهد که به‌عنوان پاک‌کن با TOOL_TYPE_ERASER استفاده می‌شود:

val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)

داده‌های محور قلم

ACTION_DOWN و ACTION_MOVE داده‌های محور را درباره قلم ارائه می‌دهند، یعنی مختصات x و y، فشار، جهت، کج کردن، و نگه داشتن.

برای فعال کردن دسترسی به این داده‌ها، MotionEvent API getAxisValue(int) را ارائه می‌دهد، که در آن پارامتر یکی از شناسه‌های محور زیر است:

Axis برگرداندن مقدار getAxisValue()
AXIS_X مختصات X رویداد حرکتی.
AXIS_Y مختصات Y رویداد حرکتی.
AXIS_PRESSURE برای صفحه لمسی یا پد لمسی، فشاری که توسط انگشت، قلم، یا اشاره‌گر دیگر اعمال می‌شود. برای موشواره یا گوی پیمایش، اگر دکمه اصلی فشار داده شود، ۱ و درغیراین‌صورت، ۰.
AXIS_ORIENTATION برای صفحه لمسی یا صفحه لمسی، جهت انگشت، قلم، یا اشاره‌گر دیگر نسبت به صفحه عمودی دستگاه.
AXIS_TILT زاویه شیب قلم برحسب رادیان.
AXIS_DISTANCE فاصله قلم از صفحه.

برای مثال، MotionEvent.getAxisValue(AXIS_X) مختصات x را برای نشانگر اول برمی‌گرداند.

همچنین به مدیریت اشاره‌های چندلمسی مراجعه کنید.

موقعیت

می‌توانید مختصات x و y اشاره‌گر را با فراخوانی‌های زیر بازیابی کنید:

قلم لمسی درحال کشیدن روی صفحه‌نمایش با مختصات x و y نگاشت‌شده.
شکل ۱. مختصات x و y صفحه‌نمایش برای اشاره‌گر قلم.

فشار

می‌توانید فشار اشاره‌گر را با MotionEvent#getAxisValue(AXIS_PRESSURE) یا، برای اشاره‌گر اول، MotionEvent#getPressure() بازیابی کنید.

مقدار فشار برای صفحه‌های لمسی یا صفحه‌های لمسی مقداری بین ۰ (بدون فشار) و ۱ است، اما بسته به کالیبراسیون صفحه، مقادیر بالاتری نیز می‌تواند برگردانده شود.

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

جهت‌‌

جهت نشان می‌دهد که قلم به‌سمت کدام جهت است.

جهت اشاره‌گر را می‌توان بااستفاده از getAxisValue(AXIS_ORIENTATION) یا getOrientation() (برای اشاره‌گر اول) بازیابی کرد.

برای قلم، جهت به‌عنوان مقدار رادیان بین ۰ تا pi (𝛑) در جهت عقربه‌های ساعت یا ۰ تا pi- در خلاف جهت عقربه‌های ساعت برگردانده می‌شود.

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

شکل ۳. قلم به‌سمت چپ با زاویه حدود منفی ۰٫۵۷ رادیان اشاره می‌کند.

شیب

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

«شیب» زاویه مثبت قلم را برحسب رادیان برمی‌گرداند، که در آن صفر عمود بر صفحه‌نمایش است و 𝛑/۲ روی سطح صاف است.

زاویه کجی را می‌توان بااستفاده از getAxisValue(AXIS_TILT) بازیابی کرد (میان‌بری برای نشانگر اول وجود ندارد).

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

قلم با زاویه حدود ۴۰ درجه نسبت به سطح صفحه‌نمایش کج شده است.
شکل ۴. قلم با زاویه حدود ۰٫۷۸۵ رادیان یا ۴۵ درجه نسبت‌به خط عمود کج شده است.

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

فاصله قلم از صفحه را می‌توان با getAxisValue(AXIS_DISTANCE) به‌دست آورد. این روش مقداری از ۰٫۰ (تماس با صفحه) تا مقادیر بالاتر را با دور شدن قلم از صفحه برمی‌گرداند. فاصله شناور بین صفحه‌نمایش و نوک قلم به سازنده صفحه‌نمایش و قلم بستگی دارد. ازآنجایی‌که پیاده‌سازی‌ها می‌توانند متفاوت باشند، برای عملکردهای حیاتی برنامه به مقادیر دقیق تکیه نکنید.

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

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

توجه: Compose اصلاح‌گرهایی ارائه می‌دهد که بر حالت تعاملی عناصر میانای کاربر تأثیر می‌گذارند:

  • hoverable: پیکربندی مؤلفه برای شناور شدن بااستفاده از رویدادهای ورود و خروج اشاره‌گر.
  • indication: جلوه‌های دیداری را برای این مؤلفه هنگام وقوع تعاملات ترسیم می‌کند.

رد کردن لمس کف دست، پیمایش، و ورودی‌های ناخواسته

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

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

ACTION_CANCEL و FLAG_CANCELED

ACTION_CANCEL و FLAG_CANCELED هر دو طراحی شده‌اند تا به شما اطلاع دهند که مجموعه MotionEvent قبلی باید از آخرین ACTION_DOWN لغو شود، بنابراین می‌توانید، برای مثال، آخرین حرکت قلم را برای برنامه طراحی برای اشاره‌گر داده‌شده واگرد کنید.

ACTION_CANCEL

در Android 1.0 (سطح میانای برنامه‌سازی کاربردی ۱) اضافه شد

ACTION_CANCEL نشان می‌دهد که مجموعه قبلی رویدادهای حرکتی باید لغو شود.

‫ACTION_CANCEL زمانی فعال می‌شود که هریک از موارد زیر شناسایی شود:

  • اشاره‌های پیمایش
  • رد کردن کف دست

وقتی ACTION_CANCEL راه‌اندازی شد، باید اشاره‌گر فعال را با getPointerId(getActionIndex()) شناسایی کنید. سپس خط ایجادشده با آن اشاره‌گر را از سابقه ورودی بردارید و صحنه را دوباره رندر کنید.

FLAG_CANCELED

در Android 13 (سطح میانای برنامه‌سازی کاربردی ۳۳) اضافه شده است

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

به‌صورت زیر به مقدار پرچم دسترسی پیدا می‌کنید:

val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED

اگر پرچم تنظیم شده است، باید آخرین مجموعه MotionEvent را از آخرین ACTION_DOWN از این اشاره‌گر واگرد کنید.

مانند ACTION_CANCEL، اشاره‌گر را می‌توان با getPointerId(actionIndex) پیدا کرد.

شکل ۶. ضربه قلم و لمس کف دست MotionEvent مجموعه ایجاد می‌کند. لمس کف دست لغو شد و نمایشگر دوباره رندر شد.

تمام‌صفحه، لبه‌تالبه، و اشاره‌های پیمایش

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

شکل ۷. اشاره تند کشیدن برای انتقال برنامه به پس‌زمینه.

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

همچنین بخش رد کردن لمس کف دست، پیمایش، و ورودی‌های ناخواسته را ببینید.

برای جلوگیری از ایجاد رویدادهای لمسی ناخواسته توسط اشاره‌های پیمایش، از روش setSystemBarsBehavior() و BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE WindowInsetsController استفاده کنید:

// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

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

تأخیر پایین

تأخیر زمانی است که سخت‌افزار، سیستم، و برنامه برای پردازش و ارائه ورودی کاربر نیاز دارند.

تأخیر = پردازش ورودی سخت‌افزار و سیستم‌عامل + پردازش برنامه + ترکیب‌بندی سیستم

  • پرداز زدن سخت‌افزاری
تأخیر باعث می‌شود که خط رندرشده از موقعیت قلم عقب بماند. فاصله بین خط ترسیم‌شده و موقعیت قلم نشان‌دهنده تأخیر است.
شکل ۸. تأخیر باعث می‌شود که خط رندرشده از موقعیت قلم عقب بماند.

منبع تأخیر

  • ثبت قلم با صفحه لمسی (سخت‌افزار): اتصال بی‌سیم اولیه وقتی قلم و سیستم‌عامل برای ثبت و همگام‌سازی با یکدیگر ارتباط برقرار می‌کنند.
  • نرخ نمونه‌برداری لمسی (سخت‌افزار): تعداد دفعاتی در ثانیه که صفحه لمسی بررسی می‌کند آیا اشاره‌گر سطح را لمس می‌کند یا نه، از ۶۰ تا ۱۰۰۰ هرتز.
  • پردازش ورودی (برنامه): اعمال رنگ، جلوه‌های گرافیکی، و تبدیل روی ورودی کاربر.
  • پرداخت گرافیکی (سیستم‌عامل + سخت‌افزار): تعویض میان‌گیر، پردازش سخت‌افزاری.

گرافیک با تأخیر کم

کتابخانه گرافیک با تأخیر کم Jetpack زمان پردازش بین ورودی کاربر و بازپرداخت روی صفحه را کاهش می‌دهد.

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

پرداز کردن میان‌گیر جلو

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

برنامه در میانگیر صفحه می‌نویسد و از میانگیر صفحه می‌خواند.
شکل ۹. پرداز کردن میان‌گیر جلو.
برنامه در چندمیان‌گیر می‌نویسد که با میان‌گیر صفحه جابه‌جا می‌شود. برنامه از بافر صفحه می‌خواند.
شکل ۱۰. پرداز چندمیان‌گیری.

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

کتابخانه با تأخیر کم از Android 10 (سطح API‏ ۲۹) و بالاتر و در دستگاه‌های ChromeOS با Android 10 (سطح API‏ ۲۹) و بالاتر دردسترس است.

وابستگی‌ها

کتابخانه با تأخیر کم مؤلفه‌هایی را برای پیاده‌سازی رندر میان‌گیر جلو ارائه می‌دهد. کتابخانه به‌عنوان وابستگی در فایل build.gradle ماژول برنامه اضافه شده است:

dependencies {
    implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}

پاسخ‌های تماس GLFrontBufferRenderer

کتابخانه با تأخیر کم شامل میانای GLFrontBufferRenderer.Callback است که روش‌های زیر را تعریف می‌کند:

کتابخانه با تأخیر کم درباره نوع داده‌ای که با GLFrontBufferRenderer استفاده می‌کنید نظری ندارد.

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

بازخوانی‌ها

برای فعال کردن بازخوانی‌های پردازشی، GLFrontBufferedRenderer.Callback را اجرا کنید و onDrawFrontBufferedLayer() و onDrawDoubleBufferedLayer() را لغو کنید. GLFrontBufferedRenderer از فراخوانی‌های برگشتی برای ارائه داده‌های شما به بهینه‌ترین شکل ممکن استفاده می‌کند.

val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {
   override fun onDrawFrontBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       param: DATA_TYPE
   ) {
       // OpenGL for front buffer, short, affecting small area of the screen.
   }
   override fun onDrawMultiDoubleBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       params: Collection<DATA_TYPE>
   ) {
       // OpenGL full scene rendering.
   }
}
یک نمونه از GLFrontBufferedRenderer را اعلام کنید

GLFrontBufferedRenderer را با ارائه SurfaceView و برگشت‌های تماسی که قبلاً ایجاد کرده‌اید آماده کنید. GLFrontBufferedRenderer بااستفاده از فراخوان‌های برگشتی شما، پرداخت را برای میان‌گیر جلو و دوگانه بهینه می‌کند:

var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
درحال پرداز زدن

وقتی روش renderFrontBufferedLayer() را فراخوانی می‌کنید، رندر کردن میان‌گیر جلو شروع می‌شود و این کار باعث راه‌اندازی فراخوانی onDrawFrontBufferedLayer() می‌شود.

وقتی تابع commit() را فراخوانی می‌کنید، پرداز با میان‌گیر دوگانه ازسر گرفته می‌شود و این کار باعث راه‌اندازی فراخوان برگشتی onDrawMultiDoubleBufferedLayer() می‌شود.

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

می‌توانید از requestUnbufferedDispatch() استفاده کنید تا درخواست کنید سیستم ورودی رویدادهای حرکتی را دسته‌بندی نکند، بلکه آن‌ها را به‌محض دردسترس قرار گرفتن ارائه دهد:

when (motionEvent.action) {
   MotionEvent.ACTION_DOWN -> {
       // Deliver input events as soon as they arrive.
       view.requestUnbufferedDispatch(motionEvent)
       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_MOVE -> {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_UP -> {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit()
   }
   MotionEvent.CANCEL -> {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel()
   }
}

بایدها و نبایدهای پرداز زدن

✓ موارد مجاز

بخش‌های کوچکی از صفحه‌نمایش، دست‌نویسی، نقاشی، طراحی.

✗ نبایدها

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

پارگی

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

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

پیش‌بینی حرکت

کتابخانه پیش‌بینی حرکت Jetpack با تخمین زدن مسیر ضربه کاربر و ارائه نقاط مصنوعی موقت به رندرکننده، تأخیر درک‌شده را کاهش می‌دهد.

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

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

کتابخانه پیش‌بینی حرکت از Android 4.4 (سطح API‏ ۱۹) و بالاتر و در دستگاه‌های ChromeOS دارای Android 9 (سطح API‏ ۲۸) و بالاتر دردسترس است.

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

وابستگی‌ها

کتابخانه پیش‌بینی حرکت، پیاده‌سازی پیش‌بینی را ارائه می‌دهد. کتابخانه به‌عنوان وابستگی در فایل build.gradle ماژول برنامه اضافه شده است:

dependencies {
    implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}

پیاده‌سازی

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

  • record(): MotionEvent شیء را به‌عنوان سابقه‌ای از کنش‌های کاربر ذخیره می‌کند
  • predict(): MotionEvent پیش‌بینی‌شده را برمی‌گرداند
نمونه‌ای از MotionEventPredictor را اعلام کنید
var motionEventPredictor = MotionEventPredictor.newInstance(view)
تغذیه پیش‌بینی‌کننده با داده‌ها
motionEventPredictor.record(motionEvent)
پیش‌بینی کردن

when (motionEvent.action) {
   MotionEvent.ACTION_MOVE -> {
       val predictedMotionEvent = motionEventPredictor?.predict()
       if(predictedMotionEvent != null) {
            // use predicted MotionEvent to inject a new artificial point
       }
   }
}

بایدها و نبایدهای پیش‌بینی حرکت

✓ موارد مجاز

وقتی نقطه پیش‌بینی‌شده جدیدی اضافه می‌شود، نقاط پیش‌بینی را بردارید.

✗ نبایدها

از نقاط پیش‌بینی برای پرداخت نهایی استفاده نکنید.

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

ChromeOS به برنامه شما امکان می‌دهد برخی‌از کنش‌های یادداشت‌برداری را اعلام کند.

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

برای ثبت برنامه به‌عنوان برنامه یادداشت‌برداری در Android، به ایجاد برنامه یادداشت‌برداری مراجعه کنید.

Android 14 (سطح میانای برنامه‌سازی کاربردی ۳۴) ACTION_CREATE_NOTE را معرفی کرد که به برنامه شما امکان می‌دهد فعالیت یادداشت‌برداری را در صفحه قفل شروع کند.

تشخیص جوهر دیجیتال با ML Kit

با تشخیص جوهر دیجیتال ML Kit، برنامه شما می‌تواند نوشتار دست‌نویس را روی سطح دیجیتال به صدها زبان تشخیص دهد. همچنین می‌توانید طرح‌ها را طبقه‌بندی کنید.

«کیت یادگیری ماشین» کلاس Ink.Stroke.Builder را برای ایجاد اشیاء Ink ارائه می‌دهد که می‌توانند توسط مدل‌های یادگیری ماشین پردازش شوند تا دست‌نوشته را به نوشتار تبدیل کنند.

علاوه‌بر تشخیص دست‌نویس، این مدل می‌تواند اشاره‌ها مثل حذف و دایره کشیدن را تشخیص دهد.

برای کسب اطلاعات بیشتر، به تشخیص جوهر دیجیتال مراجعه کنید.

منابع بیشتر

راهنمای توسعه‌دهندگان

Codelabs