绘制笔画

为了实现最佳绘制性能,请使用 InProgressStrokesView 类的 startStroke()addToStroke()finishStroke() 方法,并将 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

    在 activity 或 fragment 的 [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_CANCELFLAG_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, ...  }  } }