ל-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
מספק נתונים שקשורים להיבטים הבאים של ממשק המשתמש
אירוע:
- פעולות: אינטראקציה פיזית עם המכשיר – נגיעה במסך, מעבירים את הסמן מעל פני המסך, מעבירים את העכבר מעל המסך. פלטפורמה
- מצביעים: מזהים של אובייקטים שמקיימים אינטראקציה עם המסך – אצבעות סטיילוס, עכבר
- ציר: סוג הנתונים – קואורדינטות 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 וגם
הקואורדינטות, לחץ, כיוון, הטיה והעברה של העכבר מעל.
כדי לאפשר גישה לנתונים האלה, ה-API של MotionEvent
מספק
getAxisValue(int)
,
כאשר הפרמטר הוא אחד ממזהי הציר הבאים:
Axis | הערך המוחזר של getAxisValue() |
---|---|
AXIS_X |
קואורדינטת ה-X של אירוע תנועה. |
AXIS_Y |
קואורדינטת ה-Y של אירוע תנועה. |
AXIS_PRESSURE |
במסך מגע או בלוח מגע, הלחץ שמופעל על ידי אצבע, סטיילוס או מצביע אחר. לעכבר או לכדור עקיבה, מזינים 1 אם לוחצים על הלחצן הראשי, ואם לא, מזינים 0. |
AXIS_ORIENTATION |
במסך מגע או בלוח מגע, הכיוון של אצבע, סטיילוס או מצביע אחר ביחס למישור האנכי של המכשיר. |
AXIS_TILT |
זווית ההטיה של הסטיילוס ברדיאנים. |
AXIS_DISTANCE |
המרחק של הסטיילוס מהמסך. |
לדוגמה, MotionEvent.getAxisValue(AXIS_X)
מחזירה את קואורדינטת ה-x של
הסמן הראשון.
כדאי לעיין גם במאמר טיפול בריבוי מגע תנועות.
מיקום
ניתן לאחזר את הקואורדינטות x ו-y של מצביע באמצעות הקריאות הבאות:
MotionEvent#getAxisValue(AXIS_X)
אוMotionEvent#getX()
MotionEvent#getAxisValue(AXIS_Y)
אוMotionEvent#getY()
הלחץ
אפשר לאחזר את לחץ המצביע באמצעות
MotionEvent#getAxisValue(AXIS_PRESSURE)
, או, עבור הסמן הראשון,
MotionEvent#getPressure()
.
ערך הלחץ במסכי מגע או בלוחות מגע הוא ערך בין 0 (לא ) ו-1, אבל ניתן להחזיר ערכים גבוהים יותר בהתאם למסך כיול.
כיוון
כיוון התצוגה מציין לאיזה כיוון הסטיילוס פונה.
ניתן לאחזר את כיוון המצביע באמצעות getAxisValue(AXIS_ORIENTATION)
או
getOrientation()
(לסמן הראשון).
עבור סטיילוס, הכיוון מוחזר כערך רדיאני בין 0 לפאי (נעזרים ב חלק #) בכיוון השעון או אפס עד פאי נגד כיוון השעון.
כיוון התצוגה מאפשר להשתמש במברשת מהחיים האמיתיים. לדוגמה, אם סטיילוס מייצג מברשת שטוחה, רוחב המברשת השטוחה תלוי בכיוון הסטיילוס.
הטיה
ההטיה מודדת את הנטייה של הסטיילוס ביחס למסך.
הטיה מחזירה את הזווית החיובית של הסטיילוס ברדיאנים, כאשר אפס הוא מאונך למסך ו-סידור 2/2 מופיע באופן שטוח על פני השטח.
ניתן לאחזר את זווית ההטיה באמצעות getAxisValue(AXIS_TILT)
(אין קיצור דרך
את הסמן הראשון).
ניתן להשתמש בהטיה כדי לשחזר כלים אמיתיים ככל האפשר, כמו שמחקה הצללה עם עיפרון מוטה.
ריחוף
אפשר לאתר את המרחק של הסטיילוס מהמסך באמצעות
getAxisValue(AXIS_DISTANCE)
השיטה מחזירה ערך מ-0.0 (יצירת קשר עם
מהמסך) לערכים גבוהים יותר כשהסטיילוס מתרחק מהמסך. העברת העכבר מעל
המרחק בין המסך לבין הסיב (הנקודה) של הסטיילוס תלוי
יצרן המסך וגם הסטיילוס. כי הטמעות יכולות
שונים, אל תסתמכו על ערכים מדויקים לפונקציונליות קריטית של אפליקציה.
אפשר להשתמש בעכבר עם סטיילוס כדי לראות תצוגה מקדימה של גודל המברשת או כדי לציין הלחצן ייבחר.
הערה: בכתיבה יש מגבילי התאמה שמשפיעים על המצב האינטראקטיבי של רכיבי ממשק המשתמש:
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())
. לאחר מכן, מסירים מהיסטוריית הקלט את הקו שנוצר עם הסמן ומעבדים מחדש את הסצנה.
FLAG_CANCELED
נוסף ב-Android 13 (רמת API 33)
FLAG_CANCELED
מציין שהסמן שמצביע למעלה נגע לא מכוון של המשתמש. הדגל הוא
מוגדרות בדרך כלל כשהמשתמש נוגע בטעות במסך, למשל על ידי לחיצה
את המכשיר או מניחים את כף היד על המסך.
כדי לגשת לערך הדגל:
val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED
אם הדגל מוגדר, צריך לבטל את ההגדרה האחרונה של MotionEvent
,
ACTION_DOWN
מהסמן הזה.
כמו ACTION_CANCEL
, אפשר למצוא את הסמן באמצעות getPointerId(actionIndex)
.
מסך מלא, מקצה לקצה ותנועות ניווט
אם האפליקציה מוצגת במסך מלא וכוללת רכיבים שניתן לבצע בהם פעולה קרוב לקצה שלה, כמו קנבס של אפליקציה לרישום הערות, שמחליק מתחתית המסך כדי הצגת הניווט או העברת האפליקציה לרקע עלולים לגרום מגע לא רצוי בהדפסה על קנבס.
כדי למנוע מתנועות להפעיל נגיעות לא רצויות באפליקציה, אפשר לבצע
את היתרון של insets
ACTION_CANCEL
.
כדאי לעיין גם במאמר דחייה של כף היד, ניווט ושיטות קלט לא רצויות. .
משתמשים ב
setSystemBarsBehavior()
method ו-
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
מתוך
WindowInsetsController
כדי למנוע מתנועות ניווט לגרום לאירועי מגע לא רצויים:
// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
למידע נוסף על ניהול תנועות וכניסת תנועות, ראו:
זמן אחזור קצר
זמן האחזור הוא משך הזמן שנדרש על ידי החומרה, המערכת והאפליקציה לעיבוד ולעבד את הקלט של המשתמשים.
זמן אחזור = עיבוד קלט של חומרה ומערכת הפעלה + עיבוד אפליקציות + הרכבה של המערכת
- רינדור חומרה
מקור זמן האחזור
- רישום סטיילוס עם מסך מגע (חומרה): חיבור אלחוטי ראשוני כשהסטיילוס ומערכת ההפעלה מתקשרים לצורך רישום וסנכרון.
- קצב דגימת מגע (חומרה): מספר הפעמים בשנייה שמסך מגע הפונקציה בודקת אם מצביע נוגע לפני השטח, בטווח של 60 עד 1,000 הרץ.
- עיבוד קלט (אפליקציה): שימוש בצבע, באפקטים גרפיים ובטרנספורמציה בתגובה לקלט של משתמשים.
- עיבוד גרפי (OS + חומרה): החלפת מאגר נתונים זמני, עיבוד חומרה.
גרפיקה עם זמן אחזור קצר
ספריית הגרפיקה עם זמן אחזור קצר של Jetpack מקצר את זמן העיבוד בין קלט של משתמשים לבין רינדור על המסך.
הספרייה מקצרת את זמן העיבוד על ידי הימנעות מעיבוד של מאגר נתונים זמני מינוף שיטת עיבוד של מאגר נתונים זמני קדמי, כלומר לכתוב ישירות במסך.
עיבוד מאגר נתונים זמני קדמי
מאגר הנתונים הזמני הוא הזיכרון שמשמש את המסך לעיבוד. זה הכי קרוב אפליקציות יכולות לגשת לשרטוט ישירות במסך. הספרייה עם זמן האחזור הקצר מפעילה כדי לעבד אותן ישירות למאגר הנתונים הקדמי. זה משפר את הביצועים על ידי למניעת החלפת מאגר נתונים זמני, שעלולה להתרחש במהלך רינדור רגיל של מאגר נתונים זמני או לעיבוד של מאגר נתונים זמני כפול (התרחיש הנפוץ ביותר).
למרות שעיבוד מאגר הנתונים הקדמי הוא שיטה מצוינת ליצירת שטח קטן הוא לא מיועד לשימוש לרענון כל המסך. ב- בתהליך רינדור מראש, האפליקציה מעבדת את התוכן למאגר נתונים זמני שממנו המסך קורא נתונים. כתוצאה מכך, יש אפשרות לעיבוד פריטים או קריעות (ראו בהמשך).
הספרייה עם זמן אחזור קצר זמינה ב-Android 10 (API ברמה 29) ואילך ובמכשירי ChromeOS עם Android מגרסה 10 (API ברמה 29) ואילך.
יחסי תלות
הספרייה עם זמן האחזור הקצר מספקת את הרכיבים לעיבוד של מאגר הנתונים הזמני
יישום בפועל. הספרייה מתווספת כתלות במודול של האפליקציה
קובץ build.gradle
:
dependencies {
implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}
קריאות חוזרות (callback) של GLFrontBufferRenderer
הספרייה עם זמן האחזור הקצר כוללת את
GLFrontBufferRenderer.Callback
שמגדיר את השיטות הבאות:
בספרייה עם זמן האחזור הקצר אין חשיבות לסוג הנתונים שאתם משתמשים בהם
GLFrontBufferRenderer
עם זאת, הספרייה מעבדת את הנתונים כזרם של מאות נקודות נתונים. וכך, לתכנן את הנתונים שלכם באופן לאופטימיזציה של השימוש וההקצאה בזיכרון.
התקשרות חזרה
כדי להפעיל רינדור קריאות חוזרות (callback) ברינדור, צריך להטמיע את GLFrontBufferedRenderer.Callback
לשנות את onDrawFrontBufferedLayer()
ואת onDrawDoubleBufferedLayer()
.
GLFrontBufferedRenderer
משתמש בקריאות החוזרות (callback) כדי לעבד את הנתונים שלך במידה הרבה ביותר
בצורה אופטימלית.
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
הקריאות החוזרות (callback) שיצרתם קודם. GLFrontBufferedRenderer
מבצע אופטימיזציה של הרינדור
לחזית ולמאגר הנתונים הזמני באמצעות קריאות חוזרות (callback):
var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
רינדור
רינדור מאגר הנתונים הזמני מתחיל כשקוראים לפונקציה
renderFrontBufferedLayer()
השיטה הזו, שמפעילה את הקריאה החוזרת (callback) של onDrawFrontBufferedLayer()
.
הרינדור של מאגר הנתונים הזמני ימשיך לפעול כשקוראים
commit()
שמפעילה את הקריאה החוזרת (callback) של 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()
}
}
מה צריך לעשות ומה לא צריך לעשות
חלקים קטנים מהמסך, כתב יד, שרטוט, רישום.
עדכון מסך מלא, הזזה, שינוי מרחק התצוגה. עלולה לגרום לקריסה.
קרעים
קריסת המסך מתרחשת כשהמסך מתרענן בזמן שמאגר הנתונים הזמני של המסך פועל בו-זמנית. חלק מהמסך מציג נתונים חדשים, בעוד שחלק אחר במסך מציגה נתונים ישנים.
חיזוי תנועה
חיזוי התנועה של Jetpack ספרייה זמן אחזור נתפס על ידי הערכת נתיב הקו של המשתמש ומתן נתונים זמניים, נקודות מלאכותיות לכלי לרינדור.
ספריית החיזוי של התנועה מקבלת קלט אמיתי ממשתמשים כאובייקטים MotionEvent
.
האובייקטים מכילים מידע על הקואורדינטות, לחץ וזמן.
שבהן מתבססים חיזוי התנועה כדי לחזות את העתיד של MotionEvent
אובייקטים.
אובייקטים חזויים של MotionEvent
הם אומדנים בלבד. מספר האירועים החזויים עשוי לרדת
זמן האחזור שנתפס, אבל צריך להחליף את הנתונים החזויים ב-MotionEvent
בפועל
לאחר שהם התקבלו.
ספריית החיזוי של התנועה זמינה מ-Android 4.4 (רמת API 19) במכשירי ChromeOS עם Android 9 מגרסה 28 (רמת API 28) ואילך.
יחסי תלות
ספריית החיזוי של התנועה מספקת את החיזוי.
הספרייה מתווספת כתלות בקובץ המודול 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, אפשר לעיין במאמר יצירת כתיבת הערות app.
ב-Android 14 (רמת API 34), הושקה
ACTION_CREATE_NOTE
Intent, שמאפשר לאפליקציה להתחיל רישום הערות במנעול
מסך.
זיהוי דיו דיגיטלי באמצעות ערכת ML
בעזרת הדיו הדיגיטלי של ML Kit וזיהוי אובייקטים, האפליקציה יכולה לזהות טקסט בכתב יד על משטח דיגיטלי בשפות שונות. אפשר גם לסווג שרטוטים.
ערכת למידת המכונה מספקת
Ink.Stroke.Builder
הכיתה כדי ליצור Ink
אובייקטים שניתנים לעיבוד באמצעות מודלים של למידת מכונה
כדי להמיר כתב יד לטקסט.
בנוסף לזיהוי כתב יד, המודל יכול לזהות תנועות, כמו מחיקה ועיגול.
למידע נוסף, ראו דיו דיגיטלי זיהוי למידע נוסף.