כדי לשפר את ביצועי הציור, מומלץ להשתמש בשיטות startStroke()
, addToStroke()
ו-finishStroke()
של המחלקה InProgressStrokesView
, ולהעביר אובייקטים מסוג MotionEvent
כקלט.
הגדרת רכיב של ממשק המשתמש
משלבים את
InProgressStrokesView
בהיררכיית התצוגות המפורטות.<FrameLayout> <ScrollView android:id="@+id/my_content" android:width="match_parent" android:height="match_parent" > <!-- Your content here. --> </ScrollView> <androidx.ink.authoring.InProgressStrokesView android:id="@+id/in_progress_strokes_view" android:width="match_parent" android:height="match_parent" /> </FrameLayout>
Instant InProgressStrokesView
בתוך השיטה [
onCreate()
][ink-draw-include6] של הפעילות או של הפלח, מקבלים הפניה ל-InProgressStrokesView
ומגדירים מאזין למגע לניהול הקלט של המשתמש.class MyActivity : View.OnTouchListener { private lateinit var contentView: ScrollView private lateinit var inProgressStrokesView: InProgressStrokesView private lateinit var predictor: MotionEventPredictor // ... other variables override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) predictor = MotionEventPredictor.newInstance(contentView) contentView = findViewById(R.id.my_content) contentView.setOnTouchListener(touchListener) inProgressStrokesView = findViewById(R.id.in_progress_strokes_view) } // ... (touchListener implementation) }
טיפול באירועי מגע
אחרי שמגדירים את רכיבי ממשק המשתמש, אפשר להתחיל לצייר על סמך אירועי מגע.
פעולת
MotionEvent
השיטה
InProgressStrokesView
תיאור
התחלת העיבוד של הקווים
המשך עיבוד הקו
השלמת עיבוד הקווים
הטמעת דחייה של כף היד וביטול התנועה
class MyActivity : View.OnTouchListener { private lateinit var contentView: ScrollView private lateinit var inProgressStrokesView: InProgressStrokesView private var pointerId = -1 private var strokeId: InProgressStrokeId? = null private lateinit var predictor: MotionEventPredictor override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) contentView = findViewById(R.id.my_content) predictor = MotionEventPredictor.create(contentView) contentView.setOnTouchListener(touchListener) inProgressStrokesView = findViewById(R.id.in_progress_strokes_view) } private val touchListener = { view: View, event: MotionEvent -> predictor.record(event) when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // First pointer - treat it as inking. view.requestUnbufferedDispatch(event) val pointerIndex = event.actionIndex pointerIdToStrokeId[event.getPointerId(pointerIndex)] = inProgressStrokesView.startStroke(event, pointerId) return true } MotionEvent.ACTION_POINTER_DOWN -> { val stroke = strokeId ?: return false inProgressStrokesView.cancelStroke(stroke, event) strokeId = null pointerId = -1 return false } MotionEvent.ACTION_MOVE -> { val predictedEvent = predictor.predict() try { for (pointerIndex in 0 until pointerCount) { val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: continue inProgressStrokesView.addToStroke(event, pointerId, strokeId, predictedEvent) } finally { predictedEvent?.recycle() } } } MotionEvent.ACTION_UP -> { val pointerIndex = event.actionIndex val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false inProgressStrokesView.finishStroke(event, pointerId, strokeId) return true } MotionEvent.ACTION_CANCEL -> { val pointerIndex = event.actionIndex val strokeId = pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false inProgressStrokesView.cancelStroke(strokeId, event) return true } } return false } }
טיפול בתנועות שהסתיימו
כשקוראים לפונקציה
finishStroke()
, הקו מסומן כהשלמה. עם זאת, תהליך הסיכום אינו מיידי. הקו מעובד במלואו והאפליקציה יכולה לגשת אליו זמן קצר אחרי הקריאה ל-finishStroke()
, במיוחד כשאין קווים אחרים בתהליך עיבוד. כך אפשר לוודא שכל פעולות השרטוט יסתיימו לפני שהשבץ יועבר ללקוח כסיום.יש שתי אפשרויות לאחזר את התנועות שהושלמו:
- מטמיעים את הממשק
InProgressStrokesFinishedListener
בפעילות או ב-ViewModel, ורושמים את המאזינים באמצעותInProgressStrokesView
באמצעותaddFinishedStrokesListener
. - משתמשים ב-method
getFinishedStrokes()
שלInProgressStrokesView
כדי לקבל ישירות את כל הקווים הסופיים.
class MyActivity : ComponentActivity(), InProgressStrokesFinishedListener { ... private val finishedStrokesState = mutableStateOf(emptySet<Stroke>()) override fun onCreate(savedInstanceState: Bundle?) { ... inProgressStrokesView.addFinishedStrokesListener(this) } // ... (handle touch events) @UiThread override fun onStrokesFinished(strokes: Map<InProgressStrokeId, Stroke>) { finishedStrokesState.value += strokes.values inProgressStrokesView.removeFinishedStrokes(strokes.keys) } }
אחרי שאתם מאחזרים את הקווים הסופיים, אתם יכולים להשתמש ב-
ViewStrokeRenderer
כאבסוקציה ברמה גבוהה יותר שנוצרה על גביCanvasStrokeRenderer
. כך תוכלו לפשט את תהליך העיבוד בהיררכיית התצוגות.class DrawingView(context: Context) : View(context) { private val viewStrokeRenderer = ViewStrokeRenderer(myCanvasStrokeRenderer, this) override fun onDraw(canvas: Canvas) { viewStrokeRenderer.drawWithStrokes(canvas) { scope -> canvas.scale(myZoomLevel) canvas.rotate(myRotation) canvas.translate(myPanX, myPanY) scope.drawStroke(myStroke) // Draw other objects including more strokes, apply more transformations, ... } } }
- מטמיעים את הממשק