Optimum çizim performansı elde etmek için InProgressStrokesView
sınıfının startStroke()
, addToStroke()
ve finishStroke()
yöntemlerini kullanın. Bu yöntemlerde, giriş olarak MotionEvent
nesneleri iletin.
Kullanıcı arayüzü bileşenini ayarlama
Çiziminizin composable işlevine bir
AndroidView
composable (composable) ekleyin.@Composable fun DrawingView() { Box(modifier = Modifier.fillMaxSize()) { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> val rootView = FrameLayout(context) //... }, ) { } } }
InProgressStrokesView'ı başlatma
Etkinliğinizin
onCreate()
yöntemindeInProgressStrokesView
referansı alın ve kullanıcı girişini yönetmek için bir dokunma dinleyicisi oluşturun.class MainActivity : ComponentActivity(){ private lateinit var inProgressStrokesView: InProgressStrokesView // ... other variables override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) inProgressStrokesView = InProgressStrokesView(this) setContent { // ... DrawingView(inProgressStrokesView = inProgressStrokesView) } } } @Composable fun DrawingView( inProgressStrokesView: InProgressStrokesView, ) { Box(modifier = Modifier.fillMaxSize()) { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> val rootView = FrameLayout(context) inProgressStrokesView.apply { layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, ) } val predictor = MotionEventPredictor.newInstance(rootView) val touchListener = View.OnTouchListener { view, event -> // ... (handle touch events) } rootView.setOnTouchListener(touchListener) rootView.addView(inProgressStrokesView) rootView }, ) {} } }
Dokunma etkinliklerini işleme
Kullanıcı arayüzü bileşenlerini oluşturduktan sonra dokunma etkinliklerine göre çizim başlatabilirsiniz.
MotionEvent
işlemInProgressStrokesView
yöntemiAçıklama
Çizgi oluşturmaya başlama
Çizgiyi oluşturmaya devam et
Çizgi oluşturma işlemini tamamlama
Avuç içi reddetme özelliğini uygulayın; çizgiyi iptal edin
@SuppressLint("ClickableViewAccessibility") @Composable fun DrawingSurface( inProgressStrokesView: InProgressStrokesView ) { val currentPointerId = remember { mutableStateOf<Int?>(null) } val currentStrokeId = remember { mutableStateOf<InProgressStrokeId?>(null) } val defaultBrush = Brush.createWithColorIntArgb( family = StockBrushes.pressurePenLatest, colorIntArgb = Color.Black.toArgb(), size = 5F, epsilon = 0.1F ) Box(modifier = Modifier.fillMaxSize()) { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> val rootView = FrameLayout(context) inProgressStrokesView.apply { layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, ) } val predictor = MotionEventPredictor.newInstance(rootView) val touchListener = View.OnTouchListener { view, event -> predictor.record(event) val predictedEvent = predictor.predict() try { when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // First pointer - treat it as inking. view.requestUnbufferedDispatch(event) val pointerIndex = event.actionIndex val pointerId = event.getPointerId(pointerIndex) currentPointerId.value = pointerId currentStrokeId.value = inProgressStrokesView.startStroke( event = event, pointerId = pointerId, brush = defaultBrush ) true } MotionEvent.ACTION_MOVE -> { val pointerId = checkNotNull(currentPointerId.value) val strokeId = checkNotNull(currentStrokeId.value) for (pointerIndex in 0 until event.pointerCount) { if (event.getPointerId(pointerIndex) != pointerId) continue inProgressStrokesView.addToStroke( event, pointerId, strokeId, predictedEvent ) } true } MotionEvent.ACTION_UP -> { val pointerIndex = event.actionIndex val pointerId = event.getPointerId(pointerIndex) check(pointerId == currentPointerId.value) val currentStrokeId = checkNotNull(currentStrokeId.value) inProgressStrokesView.finishStroke( event, pointerId, currentStrokeId ) view.performClick() true } MotionEvent.ACTION_CANCEL -> { val pointerIndex = event.actionIndex val pointerId = event.getPointerId(pointerIndex) check(pointerId == currentPointerId.value) val currentStrokeId = checkNotNull(currentStrokeId.value) inProgressStrokesView.cancelStroke(currentStrokeId, event) true } else -> false } } finally { predictedEvent?.recycle() } } rootView.setOnTouchListener(touchListener) rootView.addView(inProgressStrokesView) rootView }, ) { } } }
Tamamlanmış kulaçları işleme
finishStroke()
çağrıldıktan sonra çizgi tamamlandı olarak işaretlenir. Ancak, tamamlama işlemi anında gerçekleşmez. Çizgi tamamen işlenir ve özellikle devam eden başka darbe olmadığındafinishStroke()
çağrıldıktan kısa bir süre sonra uygulamanız için erişilebilir hale gelir. Bu sayede, çizgi bitti olarak istemciye aktarılmadan önce tüm çizim işlemleri tamamlanır.Bitmiş vuruşları almak için iki seçeneğiniz vardır:
- Etkinliğinize veya ViewModel'inize
InProgressStrokesFinishedListener
arayüzünü uygulayın ve dinleyiciyiaddFinishedStrokesListener
ileInProgressStrokesView
'e kaydedin. - Bitmiş tüm vuruşları doğrudan almak için
InProgressStrokesView
getFinishedStrokes()
yöntemini kullanın.
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) } }
Tamamlanan çizgileri aldıktan sonra,
CanvasStrokesRenderer
ekrana kaydetmektir.class MainActivity : ComponentActivity(), InProgressStrokesFinishedListener { private lateinit var inProgressStrokesView: InProgressStrokesView private val finishedStrokesState = MutableState<emptySet<Stroke>()> override fun onCreate(savedInstanceState: Bundle?) { inProgressStrokesView = InProgressStrokesView(this) inProgressStrokesView.addFinishedStrokesListener(this) canvasStrokeRenderer = CanvasStrokeRenderer.create() //... DrawingSurface( inProgressStrokesView = inProgressStrokesView, canvasStrokeRenderer = canvasStrokeRenderer, finishedStrokesState = finishedStrokesState ) //... } //... } @SuppressLint("ClickableViewAccessibility") @Composable fun DrawingSurface( inProgressStrokesView: InProgressStrokesView, finishedStrokesState: Set<Stroke> ) { val canvasStrokeRenderer = CanvasStrokeRenderer.create() //... Box(modifier = Modifier.fillMaxSize()) { AndroidView( //... ) Canvas(modifier = Modifier) { val canvasTransform = Matrix() drawContext.canvas.nativeCanvas.concat(canvasTransform) val canvas = drawContext.canvas.nativeCanvas finishedStrokesState.value.forEach { stroke -> canvasStrokeRenderer.draw(stroke = stroke, canvas = canvas, strokeToScreenTransform = canvasTransform) } } } }
- Etkinliğinize veya ViewModel'inize