رسم خط الرسم

في التصميمات المستندة إلى طرق العرض، عليك التعامل مع إدخالات اللمس الخاصة بالمستخدمين داخل InProgressStrokesView بالإضافة إلى MotionEventPredictor.

لتحقيق أفضل أداء في الرسم، استخدِم الطرق startStroke() وaddToStroke() وfinishStroke() للفئة InProgressStrokesView، مع تمرير عناصر MotionEvent كمدخلات:

  1. إعداد مكوّن واجهة المستخدم

    بالنسبة إلى التصميمات المستندة إلى العرض، أضِف 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>
    
  2. Instantiate InProgressStrokesView

    ضمن طريقة onCreate() للنشاط أو الجزء، احصل على مرجع إلى 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)
    }
    
  3. التعامل مع أحداث اللمس

    بعد إنشاء عناصر واجهة المستخدم، يمكنك بدء الرسم استنادًا إلى أحداث اللمس.

    MotionEvent إجراء

    طريقة InProgressStrokesView

    الوصف

    ACTION_DOWN

    startStroke()

    بدء عرض ضربات الفرشاة

    ACTION_MOVE

    addToStroke()

    تمديد الخط

    ACTION_UP

    finishStroke()

    إنهاء عمليات الإدخال والاستعداد لإنهاء شكل الضربة

    ACTION_CANCEL أو FLAG_CANCELED

    cancelStroke()

    إلغاء الضربة

    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. التعامل مع الضربات المنتهية

    بعد finishStroke()، تكون السكتة الدماغية قد اكتملت تقريبًا. تتم معالجة الضربة بالكامل وتصبح متاحة لتطبيقك عندما لا تكون هناك ضربات أخرى قيد التقدم. يضمن ذلك إكمال جميع عمليات الرسم قبل تسليم الضربة إلى العميل.

    لاسترداد الضربات المنتهية، لديك خياران:

    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 لرسمها:

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