رسم خط الرسم

لتحقيق أفضل أداء للرسم، استخدِم الدوالّ 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. إنشاء 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()، يتم وضع علامة على العنصر للإشارة إلى اكتماله. ومع ذلك، لا تتم عملية الانتهاء بشكل فوري. تتم معالجة الخطوط بالكامل ويصبح بإمكان تطبيقك الوصول إليها بعد وقت قصير من استدعاء دالة 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 كأحد الأشكال المجردة ذات المستوى الأعلى والمُنشأة على أساس 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, ...
        }
      }
    }