Çizgi çizme

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.

  1. Kullanıcı arayüzü bileşenini ayarlama

    InProgressStrokesView öğesini görünüm hiyerarşinize entegre edin.

    <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. InProgressStrokesView'ı başlatma

    Within your activity or fragment's [onCreate()][ink-draw-include6] method, obtain a reference to the InProgressStrokesView and establish a touch listener for managing user input.

    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. Dokunma etkinliklerini işleme

    Kullanıcı arayüzü bileşenlerini oluşturduktan sonra dokunma etkinliklerine göre çizim başlatabilirsiniz.

    MotionEvent işlemi

    InProgressStrokesView yöntemi

    Açıklama

    ACTION_DOWN

    startStroke()

    Vuruş oluşturmaya başlama

    ACTION_MOVE

    addToStroke()

    Çizgiyi oluşturmaya devam edin

    ACTION_UP

    finishStroke()

    Çizgi oluşturma işlemini tamamlama

    ACTION_CANCEL veya FLAG_CANCELED

    cancelStroke()

    Avuç içi reddetme özelliğini uygulayın; çizgiyi iptal edin

    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. Bitmiş vuruşları işleme

    finishStroke() çağrıldıktan sonra çizgi tamamlandı olarak işaretlenir. Ancak, tamamlama işlemi anında gerçekleşmez. Vuruş tamamen işlenir ve finishStroke() çağrıldıktan kısa bir süre sonra, özellikle de devam eden başka vuruş olmadığında uygulamanız tarafından 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:

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