Menggambar goresan

Dalam tata letak berbasis tampilan, Anda perlu menangani input sentuh pengguna di dalam InProgressStrokesView selain MotionEventPredictor.

Untuk mencapai performa gambar yang optimal, gunakan metode startStroke(), addToStroke(), dan finishStroke() dari class InProgressStrokesView, dengan meneruskan objek MotionEvent sebagai input:

  1. Menyiapkan komponen UI

    Untuk tata letak berbasis tampilan, tambahkan InProgressStrokesView ke 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>
    
  2. Buat instance InProgressStrokesView

    Dalam metode onCreate() aktivitas atau fragmen Anda, dapatkan referensi ke InProgressStrokesView dan tetapkan pemroses sentuh untuk mengelola input pengguna.

    Dalam metode [onCreate()][ink-draw-include6] aktivitas atau fragmen, dapatkan referensi ke InProgressStrokesView 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)
    }
    
  3. Menangani peristiwa sentuhan

    Setelah menetapkan komponen UI, Anda dapat memulai gambar berdasarkan peristiwa sentuhan.

    Tindakan MotionEvent

    Metode InProgressStrokesView

    Deskripsi

    ACTION_DOWN

    startStroke()

    Mulai rendering goresan

    ACTION_MOVE

    addToStroke()

    Memperpanjang goresan

    ACTION_UP

    finishStroke()

    Selesaikan input, bersiap untuk menyelesaikan geometri goresan

    ACTION_CANCEL atau FLAG_CANCELED

    cancelStroke()

    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
      }
    }
    
  4. Menangani goresan yang selesai

    Setelah finishStroke(), stroke hampir selesai. Goresan diproses sepenuhnya dan dapat diakses oleh aplikasi Anda setelah tidak ada goresan lain yang sedang berlangsung. Hal ini memastikan semua operasi penggambaran selesai sebelum goresan diserahkan ke klien.

    Untuk mengambil goresan yang telah selesai, Anda memiliki dua opsi:

    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 telah selesai, Anda dapat menggunakan ViewStrokeRenderer untuk menggambarnya:

    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, ...
        }
      }
    }