هذا الدرس العملي حول الترميز هو جزء من دورة "تطبيقات متقدّمة متوافقة مع نظام Android باستخدام لغة Kotlin". ستستفيد إلى أقصى حدّ من هذه الدورة التدريبية إذا تابعت دروس الترميز بالتسلسل، ولكن هذا ليس إلزاميًا. يمكنك الاطّلاع على جميع دورات الترميز في الدورة التدريبية على الصفحة المقصودة لدورات الترميز في "تطبيقات متقدمة متوافقة مع نظام Android باستخدام لغة Kotlin".
مقدمة
في نظام التشغيل Android، تتوفّر لك عدة أساليب لتنفيذ رسومات ثنائية الأبعاد ورسوم متحركة مخصّصة في طرق العرض.
بالإضافة إلى استخدام عناصر قابلة للرسم، يمكنك إنشاء رسومات ثنائية الأبعاد باستخدام طرق الرسم في الفئة Canvas
. Canvas
هو سطح رسم ثنائي الأبعاد يوفّر طرقًا للرسم. ويكون ذلك مفيدًا عندما يحتاج تطبيقك إلى إعادة رسم نفسه بانتظام، لأنّ ما يراه المستخدم يتغير بمرور الوقت. في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية إنشاء لوحة رسم وعرضها في View
.
تشمل أنواع العمليات التي يمكنك تنفيذها على لوحة العرض ما يلي:
- املأ لوحة العرض بالكامل باللون.
- رسم أشكال، مثل المستطيلات والأقواس والمسارات التي تم تصميمها على النحو المحدّد في عنصر
Paint
يحتوي العنصرPaint
على معلومات حول النمط واللون الخاصين بكيفية رسم الأشكال الهندسية (مثل الخط والمستطيل والشكل البيضاوي والمسارات)، أو على سبيل المثال، نوع خط النص. - تطبيق عمليات تحويل، مثل الترجمة أو تغيير الحجم أو عمليات التحويل المخصّصة
- القص، أي تطبيق شكل أو مسار على لوحة العرض لتحديد الأجزاء المرئية منها
طريقة التفكير في عملية الرسم على Android (بشكل مبسط للغاية)
الرسم في نظام التشغيل Android أو أي نظام حديث آخر هو عملية معقّدة تتضمّن طبقات من التجريدات وعمليات تحسين وصولاً إلى الأجهزة. إنّ طريقة عرض Android هي موضوع شيّق تمّت الكتابة عنه كثيرًا، وتفاصيله تتجاوز نطاق هذا الدرس التطبيقي حول الترميز.
في سياق هذا الدرس العملي والتطبيق الذي يعتمد على لوحة الرسم للعرض في وضع ملء الشاشة، يمكنك التفكير في ذلك بالطريقة التالية.
- تحتاج إلى طريقة لعرض ما ترسمه. يمكن أن يكون هذا أحد طرق العرض التي يوفّرها نظام التشغيل Android. أو، في هذا الدرس التطبيقي حول الترميز، يمكنك إنشاء طريقة عرض مخصّصة تعمل كطريقة عرض المحتوى لتطبيقك (
MyCanvasView
). - يتضمّن هذا العرض، مثل جميع طرق العرض، لوحة عرض خاصة به (
canvas
). - لتنفيذ أبسط طريقة للرسم على لوحة عرض، عليك إلغاء طريقة
onDraw()
والرسم على لوحة العرض. - عند إنشاء رسم، عليك تخزين ما رسمته سابقًا في ذاكرة التخزين المؤقت. هناك عدة طرق لتخزين البيانات مؤقتًا، إحداها في صورة نقطية (
extraBitmap
)، والأخرى هي حفظ سجلّ لما رسمته كإحداثيات وتعليمات. - لرسم الصورة النقطية المخزّنة مؤقتًا (
extraBitmap
) باستخدام واجهة برمجة التطبيقات للرسم على لوحة العرض، عليك إنشاء لوحة عرض مخزّنة مؤقتًا (extraCanvas
) للصورة النقطية المخزّنة مؤقتًا. - بعد ذلك، يمكنك الرسم على لوحة العرض المؤقت (
extraCanvas
)، ما يؤدي إلى الرسم على الصورة النقطية للعرض المؤقت (extraBitmap
). - لعرض كل ما تم رسمه على الشاشة، عليك إخبار لوحة عرض (
canvas
) العرض برسم الصورة النقطية المخزّنة مؤقتًا (extraBitmap
).
ما يجب معرفته
- كيفية إنشاء تطبيق يتضمّن نشاطًا وتصميمًا أساسيًا وتشغيله باستخدام "استوديو Android"
- كيفية ربط معالجات الأحداث بطرق العرض
- كيفية إنشاء طريقة عرض مخصّصة
أهداف الدورة التعليمية
- كيفية إنشاء
Canvas
والرسم عليه استجابةً للمس المستخدم
الإجراءات التي ستنفذّها
- أنشئ تطبيقًا يرسم خطوطًا على الشاشة استجابةً للمس المستخدم للشاشة.
- تسجيل أحداث الحركة، ورسم خطوط على لوحة عرض تظهر في عرض مخصّص بملء الشاشة على الشاشة استجابةً لهذه الأحداث
يستخدم تطبيق MiniPaint طريقة عرض مخصّصة لعرض خط استجابةً للمسات المستخدم، كما هو موضّح في لقطة الشاشة أدناه.
الخطوة 1: إنشاء مشروع MiniPaint
- أنشئ مشروع Kotlin جديدًا باسم MiniPaint يستخدم نموذج نشاط فارغ.
- افتح ملف
app/res/values/colors.xml
وأضِف اللونَين التاليَين.
<color name="colorBackground">#FFFF5500</color>
<color name="colorPaint">#FFFFEB3B</color>
- فتح "
styles.xml
" - في العنصر الرئيسي لنمط
AppTheme
المحدّد، استبدِلDarkActionBar
بـNoActionBar
. يزيل هذا الإعداد شريط الإجراءات، ما يتيح لك الرسم بملء الشاشة.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
الخطوة 2: إنشاء فئة MyCanvasView
في هذه الخطوة، عليك إنشاء طريقة عرض مخصّصة، MyCanvasView
، للرسم.
- في حزمة
app/java/com.example.android.minipaint
، أنشئ New > Kotlin File/Class باسمMyCanvasView
. - اجعل الفئة
MyCanvasView
توسّع الفئةView
وتمرّرcontext: Context
. قبول عمليات الاستيراد المقترَحة
import android.content.Context
import android.view.View
class MyCanvasView(context: Context) : View(context) {
}
الخطوة 3: ضبط MyCanvasView كطريقة عرض المحتوى
لعرض ما سترسمه في MyCanvasView
، عليك ضبطه كطريقة عرض المحتوى في MainActivity
.
- افتح ملف
strings.xml
وحدِّد سلسلة لاستخدامها في وصف محتوى العرض.
<string name="canvasContentDescription">Mini Paint is a simple line drawing app.
Drag your fingers to draw. Rotate the phone to clear.</string>
- فتح "
MainActivity.kt
" - في
onCreate()
، احذفsetContentView(R.layout.activity_main)
. - أنشئ مثيلاً من
MyCanvasView
.
val myCanvasView = MyCanvasView(this)
- تحت ذلك، اطلب ملء الشاشة لتنسيق
myCanvasView
. يمكنك إجراء ذلك من خلال ضبط العلامةSYSTEM_UI_FLAG_FULLSCREEN
علىmyCanvasView
. بهذه الطريقة، تملأ طريقة العرض الشاشة بالكامل.
myCanvasView.systemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN
- أضِف وصفًا للمحتوى.
myCanvasView.contentDescription = getString(R.string.canvasContentDescription)
- أسفل ذلك، اضبط طريقة عرض المحتوى على
myCanvasView
.
setContentView(myCanvasView)
- شغِّل تطبيقك. ستظهر لك شاشة بيضاء تمامًا، لأنّ لوحة العرض ليس لها حجم ولم ترسم أي شيء بعد.
الخطوة 1: تجاوز onSizeChanged()
يستدعي نظام Android الطريقة onSizeChanged()
كلما تغيّر حجم العرض. بما أنّ العرض يبدأ بدون حجم، يتم أيضًا استدعاء طريقة onSizeChanged()
الخاصة بالعرض بعد أن ينشئ النشاط العرض ويوسّعه لأول مرة. لذلك، تُعدّ onSizeChanged()
هذه الطريقة المكان المثالي لإنشاء لوحة العرض وإعدادها.
- في
MyCanvasView
، على مستوى الفئة، حدِّد متغيّرات للوحة الرسم والصورة النقطية. اتّصِل بالرقمينextraCanvas
وextraBitmap
. هذه هي الصورة النقطية ولوحة الرسم لتخزين ما تم رسمه سابقًا مؤقتًا.
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
- حدِّد متغيّرًا على مستوى الفئة
backgroundColor
للون الخلفية في لوحة الرسم، واضبط قيمته الأولية علىcolorBackground
الذي حدّدته سابقًا.
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.colorBackground, null)
- في
MyCanvasView
، ألغِ طريقةonSizeChanged()
. يتم استدعاء طريقة معاودة الاتصال هذه من خلال نظام التشغيل Android مع أبعاد الشاشة المتغيرة، أي مع عرض وارتفاع جديدَين (للتغيير إلى) وعرض وارتفاع قديمَين (للتغيير منهما).
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
super.onSizeChanged(width, height, oldWidth, oldHeight)
}
- داخل
onSizeChanged()
، أنشئ مثيلاً منBitmap
باستخدام العرض والارتفاع الجديدَين، وهما حجم الشاشة، وعيّنهما إلىextraBitmap
. الوسيطة الثالثة هي إعدادات ألوان الصورة النقطية. تخزّنARGB_8888
كل لون في 4 بايت ويُنصح باستخدامها.
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
- أنشئ مثيلاً من
Canvas
منextraBitmap
وأسنده إلىextraCanvas
.
extraCanvas = Canvas(extraBitmap)
- تحديد لون الخلفية الذي سيتم ملء
extraCanvas
به
extraCanvas.drawColor(backgroundColor)
- بالنظر إلى
onSizeChanged()
، يتم إنشاء صورة نقطية ولوحة رسم جديدتين في كل مرة يتم فيها تنفيذ الدالة. أنت بحاجة إلى صورة نقطية جديدة لأنّ الحجم قد تغيّر. ومع ذلك، يحدث تسرُّب للذاكرة، ما يؤدي إلى بقاء الصور النقطية القديمة. لحلّ هذه المشكلة، أعِد استخدامextraBitmap
قبل إنشاء العنصر التالي عن طريق إضافة هذا الرمز مباشرةً بعد طلبsuper
.
if (::extraBitmap.isInitialized) extraBitmap.recycle()
الخطوة 2: تجاوز onDraw()
يتم تنفيذ جميع أعمال الرسم الخاصة بـ MyCanvasView
في onDraw()
.
للبدء، اعرض لوحة الرسم، واملأ الشاشة بلون الخلفية الذي ضبطته في onSizeChanged()
.
- تجاوز
onDraw()
ورسم محتوىextraBitmap
المخزّن مؤقتًا على لوحة الرسم المرتبطة بطريقة العرض تتوفّر الطريقةdrawBitmap()
Canvas
بعدّة إصدارات. في هذا الرمز، يمكنك تقديم الصورة النقطية وإحداثيات x وy (بالبكسل) للزاوية العلوية اليسرى وnull
للـPaint
، لأنّك ستضبط ذلك لاحقًا.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}
يُرجى العِلم أنّ لوحة العرض التي يتم تمريرها إلى onDraw()
ويستخدمها النظام لعرض الصورة النقطية تختلف عن تلك التي أنشأتها في طريقة onSizeChanged()
واستخدمتها للرسم على الصورة النقطية.
- شغِّل تطبيقك. من المفترض أن ترى الشاشة بأكملها مملوءة بلون الخلفية المحدّد.
من أجل الرسم، تحتاج إلى كائن Paint
يحدّد طريقة تصميم العناصر عند رسمها، وكائن Path
يحدّد ما يتم رسمه.
الخطوة 1: تهيئة عنصر Paint
- في MyCanvasView.kt، على مستوى الملف الأعلى، حدِّد قيمة ثابتة لعرض الخط.
private const val STROKE_WIDTH = 12f // has to be float
- على مستوى الفئة
MyCanvasView
، حدِّد المتغيّرdrawColor
لتخزين اللون الذي سيتم الرسم به، واضبط قيمته الأولية على الموردcolorPaint
الذي حدّدته سابقًا.
private val drawColor = ResourcesCompat.getColor(resources, R.color.colorPaint, null)
- على مستوى الفئة، أضِف أدناه متغيّرًا
paint
لكائنPaint
وقم بتهيئة هذا المتغيّر على النحو التالي.
// Set up the paint with which to draw.
private val paint = Paint().apply {
color = drawColor
// Smooths out edges of what is drawn without affecting shape.
isAntiAlias = true
// Dithering affects how colors with higher-precision than the device are down-sampled.
isDither = true
style = Paint.Style.STROKE // default: FILL
strokeJoin = Paint.Join.ROUND // default: MITER
strokeCap = Paint.Cap.ROUND // default: BUTT
strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}
color
paint
هوdrawColor
الذي حدّدته سابقًا.- تحدّد
isAntiAlias
ما إذا كان سيتم تطبيق تسوية الحواف. يؤدي ضبطisAntiAlias
علىtrue
إلى تنعيم حواف ما يتم رسمه بدون التأثير في الشكل. isDither
، عندماtrue
، يؤثر في طريقة تقليل عدد عيّنات الألوان التي تتميز بدقة أعلى من دقة الجهاز. على سبيل المثال، التمويه هو الطريقة الأكثر شيوعًا لتقليل نطاق ألوان الصور إلى 256 لونًا (أو أقل).- تحدّد السمة
style
نوع الرسم الذي سيتم تنفيذه على حد خارجي، وهو في الأساس خط. تحدّدPaint.Style
ما إذا كان الشكل الأساسي الذي يتم رسمه سيتم ملؤه أو رسم خطوطه الخارجية أو كليهما (باللون نفسه). الإعداد التلقائي هو ملء العنصر الذي يتم تطبيق الطلاء عليه. (يؤدي "التعبئة" إلى تلوين الجزء الداخلي من الشكل، بينما يتبع "الحد" المخطط التفصيلي للشكل). - تحدّد
strokeJoin
منPaint.Join
طريقة ربط الخطوط وقطاعات المنحنيات في مسار ذي حدود خارجية. القيمة التلقائية هيMITER
. - تضبط
strokeCap
شكل نهاية الخط ليكون غطاءً، وتحدّدPaint.Cap
كيفية تحديد بداية ونهاية الخطوط والمسارات التي تمّت تعبئتها. القيمة التلقائية هيBUTT
. - تحدّد
strokeWidth
عرض الخط بالبكسل. القيمة التلقائية هي عرض خط رفيع جدًا، لذا يتم ضبطها على الثابتSTROKE_WIDTH
الذي حدّدته سابقًا.
الخطوة 2: تهيئة عنصر Path
Path
هو مسار ما يرسمه المستخدم.
- في
MyCanvasView
، أضِف متغيّرًاpath
واضبط قيمته الأولية على كائنPath
لتخزين المسار الذي يتم رسمه عند تتبُّع لمسة المستخدم على الشاشة. استيرادandroid.graphics.Path
لـPath
private var path = Path()
الخطوة 1: الردّ على الحركة على الشاشة
يتم استدعاء الطريقة onTouchEvent()
في طريقة العرض كلما لمس المستخدم الشاشة.
- في
MyCanvasView
، ألغِ طريقةonTouchEvent()
لتخزين إحداثياتx
وy
التي تم تمريرها فيevent
. بعد ذلك، استخدِم تعبيرwhen
للتعامل مع أحداث الحركة عند النقر على الشاشة والتحرّك عليها ورفع الإصبع عنها. هذه هي الأحداث التي تهمّ رسم خط على الشاشة. بالنسبة إلى كل نوع من أنواع الأحداث، استدعِ طريقة مساعدة، كما هو موضّح في الرمز البرمجي أدناه. راجِع مستندات الفئةMotionEvent
للحصول على قائمة كاملة بأحداث اللمس.
override fun onTouchEvent(event: MotionEvent): Boolean {
motionTouchEventX = event.x
motionTouchEventY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> touchStart()
MotionEvent.ACTION_MOVE -> touchMove()
MotionEvent.ACTION_UP -> touchUp()
}
return true
}
- على مستوى الفئة، أضِف المتغيّرَين
motionTouchEventX
وmotionTouchEventY
الناقصَين لتخزين الإحداثيات x وy لحدث اللمس الحالي مؤقتًا (إحداثياتMotionEvent
). اضبط قيمتها الأولية على0f
.
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
- أنشئ رموزًا أولية للدوال الثلاث
touchStart()
وtouchMove()
وtouchUp()
.
private fun touchStart() {}
private fun touchMove() {}
private fun touchUp() {}
- يجب أن يتم إنشاء التعليمات البرمجية وتشغيلها، ولكن لن يظهر لك أي شيء مختلف عن الخلفية الملونة حتى الآن.
الخطوة 2: تنفيذ touchStart()
يتم استدعاء هذا الإجراء عندما يلمس المستخدم الشاشة لأول مرة.
- على مستوى الفئة، أضِف متغيرات لتخزين أحدث قيمتَين لـ x وy مؤقتًا. بعد أن يتوقف المستخدم عن الحركة ويرفع إصبع اللمس، تصبح هذه النقطة هي نقطة البداية للمسار التالي (الجزء التالي من الخط الذي سيتم رسمه).
private var currentX = 0f
private var currentY = 0f
- نفِّذ طريقة
touchStart()
على النحو التالي. أعِد ضبطpath
، وانتقِل إلى إحداثيات x-y لحدث اللمس (motionTouchEventX
وmotionTouchEventY
)، وعيِّنcurrentX
وcurrentY
لهذه القيمة.
private fun touchStart() {
path.reset()
path.moveTo(motionTouchEventX, motionTouchEventY)
currentX = motionTouchEventX
currentY = motionTouchEventY
}
الخطوة 3: تنفيذ touchMove()
- على مستوى الصف، أضِف المتغيّر
touchTolerance
واضبطه علىViewConfiguration.get(context).scaledTouchSlop
.
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop
باستخدام مسار، لن تحتاج إلى رسم كل وحدة بكسل وطلب إعادة تحميل الشاشة في كل مرة. بدلاً من ذلك، يمكنك (وسيكون عليك) إدخال مسار بين النقاط للحصول على أداء أفضل بكثير.
- إذا لم يتحرّك الإصبع إلا قليلاً، لن تحتاج إلى الرسم.
- إذا تحرّك الإصبع لمسافة أقل من
touchTolerance
، لا ترسم. - تعرض
scaledTouchSlop
المسافة بالبكسل التي يمكن أن يتحركها اللمس قبل أن يعتقد النظام أنّ المستخدم يتصفّح.
- حدِّد طريقة
touchMove()
. احسب المسافة المقطوعة (dx
،dy
)، وأنشئ منحنى بين النقطتين وخزِّنه فيpath
، وعدِّل إجماليcurrentX
وcurrentY
، وارسمpath
. بعد ذلك، اتّصِل بالرقمinvalidate()
لإعادة رسم الشاشة باستخدامpath
المعدَّل.
private fun touchMove() {
val dx = Math.abs(motionTouchEventX - currentX)
val dy = Math.abs(motionTouchEventY - currentY)
if (dx >= touchTolerance || dy >= touchTolerance) {
// QuadTo() adds a quadratic bezier from the last point,
// approaching control point (x1,y1), and ending at (x2,y2).
path.quadTo(currentX, currentY, (motionTouchEventX + currentX) / 2, (motionTouchEventY + currentY) / 2)
currentX = motionTouchEventX
currentY = motionTouchEventY
// Draw the path in the extra bitmap to cache it.
extraCanvas.drawPath(path, paint)
}
invalidate()
}
في ما يلي تفاصيل أكثر عن هذه الطريقة:
- احسب المسافة التي تمّت إزاحتها (
dx, dy
). - إذا كانت الحركة أبعد من مدى التفاوت المسموح به للمس، أضِف جزءًا إلى المسار.
- اضبط نقطة البداية للجزء التالي على نقطة نهاية هذا الجزء.
- يؤدي استخدام
quadTo()
بدلاً منlineTo()
إلى إنشاء خط مرسوم بسلاسة بدون زوايا. يُرجى الاطّلاع على منحنيات بيزير. - استدعِ الدالة
invalidate()
(لاستدعاء الدالةonDraw()
في النهاية) لإعادة رسم العرض.
الخطوة 4: تنفيذ touchUp()
عندما يرفع المستخدم إصبعه عن الشاشة، كل ما عليه فعله هو إعادة ضبط المسار حتى لا يتم رسمه مرة أخرى. لا يتم رسم أي شيء، لذا لا حاجة إلى إبطال صحة العرض.
- نفِّذ الطريقة
touchUp()
.
private fun touchUp() {
// Reset the path so it doesn't get drawn again.
path.reset()
}
- نفِّذ الرمز البرمجي واستخدِم إصبعك للرسم على الشاشة. يُرجى العِلم أنّه في حال تدوير الجهاز، سيتم محو الشاشة لأنّه لا يتم حفظ حالة الرسم. في هذا التطبيق النموذجي، تم تصميم هذه الميزة لمنح المستخدم طريقة بسيطة لمحو الشاشة.
الخطوة 5: رسم إطار حول الرسم التخطيطي
أثناء الرسم على الشاشة، ينشئ تطبيقك المسار ويحفظه في الصورة النقطية extraBitmap
. تعرض طريقة onDraw()
الصورة النقطية الإضافية في لوحة الرسم الخاصة بطريقة العرض. يمكنك الرسم أكثر في onDraw()
. على سبيل المثال، يمكنك رسم أشكال بعد رسم الصورة النقطية.
في هذه الخطوة، ارسم إطارًا حول حافة الصورة.
- في
MyCanvasView
، أضِف متغيّرًا باسمframe
يحتوي على عنصرRect
.
private lateinit var frame: Rect
- في نهاية
onSizeChanged()
، حدِّد مساحة داخلية، وأضِف رمزًا لإنشاءRect
سيتم استخدامه للإطار، باستخدام الأبعاد الجديدة والمساحة الداخلية.
// Calculate a rectangular frame around the picture.
val inset = 40
frame = Rect(inset, inset, width - inset, height - inset)
- في
onDraw()
، بعد رسم الصورة النقطية، ارسم مستطيلاً.
// Draw a frame around the canvas.
canvas.drawRect(frame, paint)
- شغِّل تطبيقك ولاحظ الإطار.
المهمة (اختيارية): تخزين البيانات في مسار
في التطبيق الحالي، يتم تخزين معلومات الرسم في صورة نقطية. على الرغم من أنّ هذا الحلّ جيد، إلا أنّه ليس الطريقة الوحيدة الممكنة لتخزين معلومات الرسومات. تعتمد طريقة تخزين سجلّ الرسومات على التطبيق ومتطلباتك المختلفة. على سبيل المثال، إذا كنت ترسم أشكالاً، يمكنك حفظ قائمة بالأشكال مع مواقعها الجغرافية وأبعادها. بالنسبة إلى تطبيق MiniPaint، يمكنك حفظ المسار بتنسيق Path
. في ما يلي الخطوط العريضة العامة حول كيفية إجراء ذلك، إذا أردت تجربته.
- في
MyCanvasView
، أزِل كل الرموز الخاصة بـextraCanvas
وextraBitmap
. - أضِف متغيرات للمسار حتى الآن والمسار الذي يتم رسمه حاليًا.
// Path representing the drawing so far
private val drawing = Path()
// Path representing what's currently being drawn
private val curPath = Path()
- في
onDraw()
، بدلاً من رسم الصورة النقطية، ارسم المسارات المخزّنة والحالية.
// Draw the drawing so far
canvas.drawPath(drawing, paint)
// Draw any current squiggle
canvas.drawPath(curPath, paint)
// Draw a frame around the canvas
canvas.drawRect(frame, paint)
- في
touchUp()
، أضِف المسار الحالي إلى المسار السابق وأعِد ضبط المسار الحالي.
// Add the current path to the drawing so far
drawing.addPath(curPath)
// Rewind the current path for the next touch
curPath.reset()
- شغِّل تطبيقك، ولن يكون هناك أي اختلاف على الإطلاق.
نزِّل الرمز البرمجي للدرس التطبيقي حول الترميز المكتمل.
$ git clone https://github.com/googlecodelabs/android-kotlin-drawing-canvas
يمكنك بدلاً من ذلك تنزيل المستودع كملف Zip وفك ضغطه وفتحه في Android Studio.
Canvas
هو سطح رسم ثنائي الأبعاد يوفّر طرقًا للرسم.- يمكن ربط
Canvas
بمثيلView
يعرضه. - يحتوي العنصر
Paint
على معلومات حول النمط واللون وكيفية رسم الأشكال الهندسية (مثل الخط والمستطيل والشكل البيضاوي والمسارات) والنص. - من الأنماط الشائعة للعمل باستخدام لوحة الرسم إنشاء طريقة عرض مخصّصة وتجاوز الطريقتَين
onDraw()
وonSizeChanged()
. - يمكنك إلغاء طريقة
onTouchEvent()
لتسجيل لمسات المستخدمين والرد عليها من خلال رسم العناصر. - يمكنك استخدام صورة نقطية إضافية لتخزين المعلومات مؤقتًا للرسومات التي تتغير بمرور الوقت. بدلاً من ذلك، يمكنك تخزين الأشكال أو المسار.
دورة Udacity التدريبية:
مستندات مطوّري تطبيقات Android:
Canvas
صفBitmap
صفView
صفPaint
صف- إعدادات
Bitmap.config
Path
صف- صفحة منحنيات بيزير على Wikipedia
- لوحة الرسم والعناصر القابلة للرسم
- سلسلة مقالات بنية الرسومات (مستوى متقدّم)
- رسومات قابلة للرسم
- onDraw()
- onSizeChanged()
MotionEvent
ViewConfiguration.get(context).scaledTouchSlop
يسرد هذا القسم مهامًا منزلية محتملة للطلاب الذين يعملون على هذا الدرس التطبيقي العملي كجزء من دورة تدريبية يقودها مدرّب. على المعلّم تنفيذ ما يلي:
- حدِّد واجبًا منزليًا إذا لزم الأمر.
- توضيح كيفية إرسال الواجبات المنزلية للطلاب
- وضع درجات للواجبات المنزلية
يمكن للمدرّبين استخدام هذه الاقتراحات بالقدر الذي يريدونه، ويجب ألا يترددوا في تكليف الطلاب بأي واجبات منزلية أخرى يرونها مناسبة.
إذا كنت تعمل على هذا الدرس العملي بنفسك، يمكنك استخدام مهام الواجب المنزلي هذه لاختبار معلوماتك.
الإجابة عن هذه الأسئلة
السؤال 1
أيّ من المكوّنات التالية مطلوبة للعمل باستخدام Canvas
؟ يُرجى اختيار جميع الإجابات المناسبة.
▢ Bitmap
▢ Paint
▢ Path
▢ View
السؤال 2
ما هو الإجراء الذي يتم تنفيذه عند الاتصال بالرقم invalidate()
(بشكل عام)؟
▢ يبطل تطبيقك ويعيد تشغيله.
▢ يمحو الرسم من الصورة النقطية.
يشير الرمز ▢ إلى أنّه يجب عدم تنفيذ الرمز السابق.
▢ يخبر النظام بأنّه عليه إعادة رسم الشاشة.
السؤال 3
ما هي وظيفة العناصر Canvas
وBitmap
وPaint
؟
▢ سطح رسم ثنائي الأبعاد، صورة نقطية معروضة على الشاشة، معلومات حول تصميم الرسم
▢ سطح رسم ثلاثي الأبعاد، صورة نقطية لتخزين المسار مؤقتًا، معلومات التنسيق للرسم
▢ سطح رسم ثنائي الأبعاد، صورة نقطية معروضة على الشاشة، تصميم للعرض
▢ ذاكرة التخزين المؤقت لمعلومات الرسم، والصورة النقطية للرسم عليها، ومعلومات التنسيق الخاصة بالرسم
للحصول على روابط تؤدي إلى دروس برمجية أخرى في هذه الدورة التدريبية، يمكنك الانتقال إلى الصفحة المقصودة للدروس البرمجية المتقدّمة حول Android بلغة Kotlin.