วาดเส้น

หากต้องการประสิทธิภาพการวาดที่ดีที่สุด ให้ใช้เมธอดของคลาส InProgressStrokesView ซึ่งได้แก่ startStroke(), addToStroke() และ finishStroke() โดยส่งออบเจ็กต์ MotionEvent เป็นอินพุต

  1. ตั้งค่าคอมโพเนนต์ UI

    ผสาน 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] ของกิจกรรมหรือ Fragment ให้รับการอ้างอิง InProgressStrokesView และสร้าง 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. จัดการเหตุการณ์การสัมผัส

    เมื่อสร้างคอมโพเนนต์ UI แล้ว คุณจะเริ่มต้นการวาดตามเหตุการณ์การสัมผัสได้

    MotionEvent action

    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() ระบบจะทำเครื่องหมายเส้นว่าเสร็จสมบูรณ์ อย่างไรก็ตาม กระบวนการสรุปจะไม่เกิดขึ้นในทันที ระบบจะประมวลผลเส้นทั้งหมดและเข้าถึงแอปพลิเคชันของคุณได้ภายในเวลาอันสั้นหลังจากเรียกใช้ finishStroke() โดยเฉพาะอย่างยิ่งเมื่อไม่มีเส้นอื่นๆ ที่กำลังดำเนินการอยู่ วิธีนี้ช่วยให้มั่นใจได้ว่าการดำเนินการวาดทั้งหมดจะเสร็จสิ้นก่อนที่จะส่งเส้นให้กับไคลเอ็นต์ในสถานะเสร็จสิ้น

    หากต้องการเรียกดูเส้นที่วาดเสร็จแล้ว คุณมี 2 ตัวเลือกดังนี้

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