ציור קו

בפריסות מבוססות-תצוגה, צריך לטפל בקלט מגע של משתמשים בתוך 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() של הפעילות או של ה-fragment, מקבלים הפניה אל InProgressStrokesView ומגדירים מאזין מגע כדי לנהל את קלט המשתמש.

    ב-method [onCreate()][ink-draw-include6] של הפעילות או המקטע שלך, לקבל הפניה אל InProgressStrokesView וליצור Touch Listener לניהול קלט של משתמשים.

    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 method

    תיאור

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