لتحقيق أفضل أداء للرسم، استخدِم الدوالّ
startStroke()
و
addToStroke()
و
و
finishStroke()
من فئة
InProgressStrokesView
، مع تمرير عناصر
MotionEvent
كإدخال.
إعداد مكوّن واجهة المستخدم
ادمج
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>
إنشاء 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) }
معالجة أحداث اللمس
بعد إنشاء مكونات واجهة المستخدم، يمكنك الآن بدء الرسم استنادًا إلى أحداث اللمس.
إجراء
MotionEvent
طريقة
InProgressStrokesView
الوصف
بدء عرض الخطوط
مواصلة عرض الخطوط
وضع اللمسات الأخيرة على عرض السكتة
تنفيذ ميزة رفض راحة اليد وإلغاء الخطوط
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 } }
معالجة الخطوط التي تم الانتهاء منها
عند الاتصال
finishStroke()
، يتم وضع علامة على العنصر للإشارة إلى اكتماله. ومع ذلك، لا تتم عملية الانتهاء بشكل فوري. تتم معالجة الخطوط بالكامل ويصبح بإمكان تطبيقك الوصول إليها بعد وقت قصير من استدعاء دالةfinishStroke()
، وتحديدًا عندما لا تكون هناك خطوط أخرى قيد التنفيذ. يضمن ذلك اكتمال جميع عمليات الرسم قبل تسليم الخطوط العميل على أنّها مكتملة.لاسترداد الخطوط التي تم الانتهاء منها، لديك خياران:
- نفِّذ واجهة
InProgressStrokesFinishedListener
داخل نشاطك أو ViewModel، وسجِّل المُستمع معInProgressStrokesView
باستخدامaddFinishedStrokesListener
. - استخدِم
getFinishedStrokes()
طريقةInProgressStrokesView
للحصول على جميع الخطوط المكتملة مباشرةً.
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, ... } } }
- نفِّذ واجهة