Untuk mencapai performa gambar yang optimal, gunakan
metode
startStroke()
,
addToStroke()
,
dan
finishStroke()
dari
class
InProgressStrokesView
, dengan meneruskan
objek
MotionEvent
sebagai input.
Menyiapkan komponen UI
Integrasikan
InProgressStrokesView
ke dalam hierarki tampilan Anda.<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>
Membuat Instance InProgressStrokesView
Dalam metode [
onCreate()
][ink-draw-include6] fragmen atau aktivitas Anda, dapatkan referensi keInProgressStrokesView
dan buat pemroses sentuh untuk mengelola input pengguna.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) }
Menangani peristiwa sentuh
Setelah menetapkan komponen UI, kini Anda dapat memulai gambar berdasarkan peristiwa sentuh.
Tindakan
MotionEvent
Metode
InProgressStrokesView
Deskripsi
Mulai rendering goresan
Lanjutkan merender goresan
Menyelesaikan rendering goresan
Mengimplementasikan penolakan telapak tangan; membatalkan goresan
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 } }
Menangani goresan yang sudah selesai
Setelah memanggil
finishStroke()
, goresan ditandai untuk selesai. Namun, proses penyelesaian tidak langsung. Goresan diproses sepenuhnya dan dapat diakses oleh aplikasi Anda segera setelahfinishStroke()
dipanggil, khususnya saat tidak ada goresan lain yang sedang berlangsung. Hal ini memastikan bahwa semua operasi gambar telah selesai sebelum goresan diserahkan kepada klien sebagai selesai.Untuk mengambil goresan yang sudah selesai, Anda memiliki dua opsi:
- Implementasikan
antarmuka
InProgressStrokesFinishedListener
dalam aktivitas atau ViewModel, dan daftarkan pemroses denganInProgressStrokesView
denganaddFinishedStrokesListener
. - Gunakan metode
getFinishedStrokes()
InProgressStrokesView
untuk mendapatkan semua goresan yang sudah selesai secara langsung.
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) } }
Setelah mengambil goresan yang sudah selesai, Anda dapat menggunakan
ViewStrokeRenderer
sebagai abstraksi tingkat tinggi yang dibuat di atasCanvasStrokeRenderer
. Hal ini dapat lebih menyederhanakan proses rendering dalam hierarki tampilan Anda.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, ... } } }
- Implementasikan
antarmuka