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

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

MotionEvent

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

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

برای دسترسی به داده‌های MotionEvent ، یک اصلاح‌کننده pointerInput به مؤلفه‌ها اضافه کنید:

@Composable
fun Greeting() {
    Text(
        text = "Hello, Android!", textAlign = TextAlign.Center, style = TextStyle(fontSize = 5.em),
        modifier = Modifier
            .pointerInput(Unit) {
                awaitEachGesture {
                    while (true) {
                        val event = awaitPointerEvent()
                        event.changes.forEach { println(it) }
                    }
                }
            },
    )
}

یک شی MotionEvent داده های مربوط به جنبه های زیر یک رویداد UI را ارائه می دهد:

  • اقدامات: تعامل فیزیکی با دستگاه - لمس کردن صفحه نمایش، حرکت یک نشانگر روی سطح صفحه نمایش، نگه داشتن نشانگر روی سطح صفحه نمایش
  • اشاره گرها: شناسه اشیایی که با صفحه در تعامل هستند - انگشت، قلم، ماوس
  • محور: نوع داده - مختصات 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() منهای 1 متغیر است.

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

اشیاء 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) ارائه می‌کند، که در آن پارامتر هر یک از شناسه‌های محور زیر است:

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

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

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

موقعیت

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

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

فشار

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

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

قلم استایلوس که نشان‌دهنده یک زنجیره فشار کم تا زیاد است. سکته مغزی باریک و ضعیف در سمت چپ است که نشان دهنده فشار کم است. سکته مغزی از چپ به راست گسترده‌تر و تیره‌تر می‌شود تا زمانی که وسیع‌ترین و تاریک‌ترین قسمت سمت راست باشد، که نشان‌دهنده بالاترین فشار است.
شکل 2. نمایش فشار - فشار کم در سمت چپ، فشار بالا در سمت راست.

جهت گیری

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

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

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

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

شکل 3. قلم به سمت چپ منهای 57/0 رادیان است.

شیب

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

Tilt زاویه مثبت قلم را بر حسب رادیان برمی‌گرداند، جایی که صفر عمود بر صفحه است و 𝛑/2 روی سطح صاف است.

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

از Tilt می توان برای بازتولید تا حد امکان ابزارهای واقعی مانند شبیه سازی سایه با مداد کج شده استفاده کرد.

شیب قلم حدود 40 درجه از سطح صفحه نمایش داشت.
شکل 4. قلم در حدود 0.785 رادیان یا 45 درجه از عمود کج شد.

شناور

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

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

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

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

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

رد کف دست، ناوبری، و ورودی های ناخواسته

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

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

ACTION_CANCEL و FLAG_CANCELED

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

ACTION_CANCEL

اضافه شده در Android 1.0 (سطح API 1)

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

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

  • حرکات ناوبری
  • رد کف دست

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

FLAG_CANCELED

اضافه شده در Android 13 (سطح API 33)

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

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

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

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

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

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

تمام صفحه، لبه به لبه، و حرکات ناوبری

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

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

برای جلوگیری از ایجاد لمس‌های ناخواسته در برنامه‌تان توسط اشاره‌ها، می‌توانید از مزایای insets و 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

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

تاخیر کم

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

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

  • رندر سخت افزاری
تأخیر باعث می شود که ضربه رندر شده از موقعیت قلم عقب بماند. شکاف بین stroke ارائه شده و موقعیت قلم نشان دهنده تاخیر است.
شکل 8. تأخیر باعث می شود که ضربه رندر شده از موقعیت قلم عقب بماند.

منبع تأخیر

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

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

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

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

رندر جلو بافر

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

برنامه در بافر صفحه می نویسد و از بافر صفحه می خواند.
شکل 9. رندر بافر جلو.
برنامه به چند بافر می نویسد که با بافر صفحه تعویض می شود. برنامه از بافر صفحه نمایش می خواند.
شکل 10. رندر چند بافر.

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

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

وابستگی ها

کتابخانه با تأخیر کم مؤلفه هایی را برای اجرای رندر جلو بافر فراهم می کند. کتابخانه به عنوان یک وابستگی در فایل 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 رندر را در بافر جلویی و دوبل با استفاده از callback های شما بهینه می کند:

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()
   }
}

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

✓ انجام دهید

بخش های کوچک صفحه، دست خط، طراحی، طراحی.

✗ نکن

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

پاره شدن

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

قسمت‌های بالایی و پایینی تصویر اندروید به دلیل پارگی هنگام تازه‌سازی صفحه، ناهمتراز هستند.
شکل 11. Tearing as screen از بالا به پایین تازه می شود.

پیش بینی حرکت

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

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

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

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

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

وابستگی ها

کتابخانه پیش بینی حرکت، اجرای پیش بینی را فراهم می کند. کتابخانه به عنوان یک وابستگی در فایل 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 (سطح API 34)، هدف ACTION_CREATE_NOTE را معرفی کرد، که به برنامه شما امکان می‌دهد فعالیت یادداشت‌برداری را در صفحه قفل شروع کند.

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

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

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

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

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

منابع اضافی

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

Codelabs

،

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

MotionEvent

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

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

برای دسترسی به داده‌های MotionEvent ، یک اصلاح‌کننده pointerInput به مؤلفه‌ها اضافه کنید:

@Composable
fun Greeting() {
    Text(
        text = "Hello, Android!", textAlign = TextAlign.Center, style = TextStyle(fontSize = 5.em),
        modifier = Modifier
            .pointerInput(Unit) {
                awaitEachGesture {
                    while (true) {
                        val event = awaitPointerEvent()
                        event.changes.forEach { println(it) }
                    }
                }
            },
    )
}

یک شی MotionEvent داده های مربوط به جنبه های زیر یک رویداد UI را ارائه می دهد:

  • اقدامات: تعامل فیزیکی با دستگاه - لمس کردن صفحه نمایش، حرکت یک نشانگر روی سطح صفحه نمایش، نگه داشتن نشانگر روی سطح صفحه نمایش
  • اشاره گرها: شناسه اشیایی که با صفحه در تعامل هستند - انگشت، قلم، ماوس
  • محور: نوع داده - مختصات 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() منهای 1 متغیر است.

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

اشیاء 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) ارائه می‌کند، که در آن پارامتر هر یک از شناسه‌های محور زیر است:

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

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

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

موقعیت

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

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

فشار

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

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

قلم استایلوس که نشان‌دهنده یک زنجیره فشار کم تا زیاد است. سکته مغزی باریک و ضعیف در سمت چپ است که نشان دهنده فشار کم است. سکته مغزی از چپ به راست گسترده‌تر و تیره‌تر می‌شود تا زمانی که وسیع‌ترین و تاریک‌ترین قسمت سمت راست باشد، که نشان‌دهنده بالاترین فشار است.
شکل 2. نمایش فشار - فشار کم در سمت چپ، فشار بالا در سمت راست.

جهت گیری

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

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

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

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

شکل 3. قلم به سمت چپ منهای 57/0 رادیان است.

شیب

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

Tilt زاویه مثبت قلم را بر حسب رادیان برمی‌گرداند، جایی که صفر عمود بر صفحه است و 𝛑/2 روی سطح صاف است.

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

از Tilt می توان برای بازتولید تا حد امکان ابزارهای واقعی مانند شبیه سازی سایه با مداد کج شده استفاده کرد.

شیب قلم حدود 40 درجه از سطح صفحه نمایش داشت.
شکل 4. قلم در حدود 0.785 رادیان یا 45 درجه از عمود کج شد.

شناور

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

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

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

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

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

رد کف دست، ناوبری، و ورودی های ناخواسته

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

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

ACTION_CANCEL و FLAG_CANCELED

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

ACTION_CANCEL

اضافه شده در Android 1.0 (سطح API 1)

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

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

  • حرکات ناوبری
  • رد کف دست

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

FLAG_CANCELED

اضافه شده در Android 13 (سطح API 33)

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

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

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

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

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

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

تمام صفحه، لبه به لبه، و حرکات ناوبری

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

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

برای جلوگیری از ایجاد لمس‌های ناخواسته در برنامه‌تان توسط اشاره‌ها، می‌توانید از مزایای insets و 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

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

تاخیر کم

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

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

  • رندر سخت افزاری
تأخیر باعث می شود که ضربه رندر شده از موقعیت قلم عقب بماند. شکاف بین stroke ارائه شده و موقعیت قلم نشان دهنده تاخیر است.
شکل 8. تأخیر باعث می شود که ضربه رندر شده از موقعیت قلم عقب بماند.

منبع تأخیر

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

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

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

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

رندر جلو بافر

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

برنامه در بافر صفحه می نویسد و از بافر صفحه می خواند.
شکل 9. رندر بافر جلو.
برنامه به چند بافر می نویسد که با بافر صفحه تعویض می شود. برنامه از بافر صفحه نمایش می خواند.
شکل 10. رندر چند بافر.

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

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

وابستگی ها

کتابخانه با تأخیر کم مؤلفه هایی را برای اجرای رندر جلو بافر فراهم می کند. کتابخانه به عنوان یک وابستگی در فایل 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 رندر را در بافر جلویی و دوبل با استفاده از callback های شما بهینه می کند:

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()
   }
}

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

✓ انجام دهید

بخش های کوچک صفحه، دست خط، طراحی، طراحی.

✗ نکن

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

پاره شدن

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

قسمت‌های بالایی و پایینی تصویر اندروید به دلیل پارگی هنگام تازه‌سازی صفحه، ناهمتراز هستند.
شکل 11. Tearing as screen از بالا به پایین تازه می شود.

پیش بینی حرکت

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

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

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

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

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

وابستگی ها

کتابخانه پیش بینی حرکت، اجرای پیش بینی را فراهم می کند. کتابخانه به عنوان یک وابستگی در فایل 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 (سطح API 34)، هدف ACTION_CREATE_NOTE را معرفی کرد، که به برنامه شما امکان می‌دهد فعالیت یادداشت‌برداری را در صفحه قفل شروع کند.

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

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

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

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

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

منابع اضافی

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

Codelabs