لتحقيق أفضل أداء للرسم، استخدِم الدوالّ
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>Instantiate 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, ... } } }- نفِّذ واجهة