כדי לשפר את ביצועי הציור, מומלץ להשתמש בשיטות 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>
יצירת מופע של 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, ... } } }
- מטמיעים את הממשק