يُعد هذا الدرس التطبيقي جزءًا من الدورة التدريبية المتقدّمة لنظام التشغيل 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 عرضًا مخصصًا لعرض خط استجابة للمسات المستخدم، كما هو موضح في لقطة الشاشة أدناه.
الخطوة الأولى: إنشاء مشروع MiniPaint
- أنشئ مشروع Kotlin جديدًا باسم MiniPaint يستخدم نموذج Empty Activity.
- افتح الملف
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">
الخطوة الثانية: إنشاء الصف MyCanvasView
في هذه الخطوة، يمكنك إنشاء عرض مخصّص، MyCanvasView
، للرسم.
- في الحزمة
app/java/com.example.android.minipaint
، أنشِئ ملفًا/صفًا جديدًا بلغة Kotlin باسمMyCanvasView
. - جعل الفئة
MyCanvasView
تمديدView
واجتيازcontext: Context
. قبول عمليات الاستيراد المقترحة
import android.content.Context
import android.view.View
class MyCanvasView(context: Context) : View(context) {
}
الخطوة الثالثة. ضبط 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)
- شغِّل تطبيقك. ستظهر لك شاشة بيضاء تمامًا، لأن لوحة الرسم لا بحجمها ولم ترسم أي شيء بعد.
الخطوة الأولى: تجاوز 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()
الخطوة الثانية: تجاوز onDraw()
يتم إجراء جميع أعمال الرسم باللغة MyCanvasView
في onDraw()
.
للبدء، اعرض اللوحة، واملأ الشاشة بلون الخلفية الذي عيّنته في onSizeChanged()
.
- يمكنك إلغاء
onDraw()
وارسم محتوىextraBitmap
المخزن مؤقتًا على اللوحة المرتبطة بالملف الشخصي. تتوفر طريقةdrawBitmap()
Canvas
بعدة إصدارات. في هذا الرمز، أنت تقدّم الصورة النقطية والإحداثيّين"س"و"ص" (بالبكسل) في أعلى يمين الشاشة، وnull
للرمزPaint
، وستضبط ذلك لاحقًا.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}
لاحظ أن اللوحة التي تم تمريرها إلى onDraw()
واستخدمها النظام لعرض الصورة الرمزية مختلفة عن تلك التي أنشأتها في الطريقة onSizeChanged()
واستخدمتها للرسم على الصورة الرمزية.
- شغِّل تطبيقك. من المفترض أن تظهر الشاشة بأكملها ممتلئة بلون الخلفية المحدد.
للرسم، تحتاج إلى عنصر Paint
يحدد كيفية تصميم العناصر عند الرسم، وPath
الذي يحدد ما يتم رسمه.
الخطوة الأولى: إعداد كائن عرض محتوى الصفحة
- في 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
الذي حدّدته سابقًا.
الخطوة الثانية: إعداد كائن المسار
Path
هو مسار ما يرسمه المستخدم.
- في
MyCanvasView
، أضِف المتغيّرpath
واضبطه باستخدام كائنPath
لتخزين المسار المرسوم عند متابعة لمس المستخدم للشاشة. استيرادandroid.graphics.Path
Path
.
private var path = Path()
الخطوة الأولى: الاستجابة للحركة على الشاشة
يتم استدعاء الطريقة 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() {}
- من المفترض أن يتم إنشاء الرمز وتشغيله، ولكن لن ترى أي شيء مختلف عن الخلفية الملونة حتى الآن.
الخطوة الثانية: تنفيذ 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
}
الخطوة الثالثة. تنفيذ touchTouch()
- على مستوى الصف، أضِف المتغيّر
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".
- واجهة
Canvas
هي مساحة رسم ثنائية الأبعاد تقدّم طرقًا للرسم. - يمكن ربط
Canvas
بمثيلView
يعرضه. - يحتوي كائن
Paint
على معلومات النمط واللون حول كيفية رسم الأشكال الهندسية (مثل الخط والمستطيل والبيضاوي والمسارات) والنص. - يتمثل أحد الأنماط الشائعة للعمل مع لوحة الرسم في إنشاء طريقة عرض مخصصة وتجاوز طريقتي
onDraw()
وonSizeChanged()
. - يمكنك إلغاء الطريقة
onTouchEvent()
لالتقاط لمسات المستخدم والرد عليها من خلال رسم العناصر. - يمكنك استخدام صورة نقطية إضافية لتخزين المعلومات مؤقتًا عن الرسومات التي تتغير بمرور الوقت. ويمكنك بدلاً من ذلك تخزين الأشكال أو مسار.
دورة Udacity:
مستندات مطوّر برامج Android:
Canvas
صفBitmap
صفView
صفPaint
صف- إعدادات
Bitmap.config
Path
صف- منحنيات بيزير على صفحة ويكيبيديا
- لوحة الرسم والسحب
- سلسلة البنية الرسومية للمقالات (متقدمة)
- رسومات قابلة للرسم
- onDraw()
- onSizeChanged()
MotionEvent
ViewConfiguration.get(context).scaledTouchSlop
يسرد هذا القسم المهام الدراسية المحتملة للطلاب الذين يعملون من خلال هذا الدرس التطبيقي حول الترميز في إطار دورة تدريبية يُديرها معلِّم. يجب أن ينفِّذ المعلّم ما يلي:
- يمكنك تخصيص واجب منزلي إذا لزم الأمر.
- التواصل مع الطلاب بشأن كيفية إرسال الواجبات المنزلية
- وضع درجات للواجبات المنزلية.
ويمكن للمعلّمين استخدام هذه الاقتراحات بقدر ما يريدون أو بقدر ما يريدون، ويجب عدم التردد في تخصيص أي واجبات منزلية أخرى مناسبة.
إذا كنت تستخدم هذا الدرس التطبيقي بنفسك، يمكنك استخدام هذه الواجبات المنزلية لاختبار معلوماتك.
الإجابة عن هذه الأسئلة
السؤال 1
أي من المكوّنات التالية مطلوبة للعمل مع Canvas
؟ يُرجى اختيار كل الإجابات المناسبة.
▢ Bitmap
▢ Paint
▢ Path
▢ View
السؤال 2
ما المقصود بمكالمة invalidate()
إلى (العبارات العامة)؟
▢ يعمل على إلغاء صلاحية تطبيقك وإعادة تشغيله.
▢ لمحو الرسم من الصورة الرمزية.
▢ يشير إلى ضرورة عدم تشغيل الرمز السابق.
▢ لإخبار النظام بأنّ عليه إعادة رسم الشاشة.
السؤال 3
ما هي وظيفة العناصر Canvas
وBitmap
وPaint
؟
▢ سطح رسم ثنائي الأبعاد، صورة نقطية معروضة على الشاشة، ومعلومات أنماط للرسم.
▢ سطح رسم ثلاثي الأبعاد، صورة نقطية للتخزين المؤقت على المسار، ومعلومات تصميم للرسم.
▢ سطح رسم ثنائي الأبعاد، يتم عرض صورة نقطية على الشاشة، ونمطها في العرض.
▢ذاكرة التخزين المؤقت للحصول على معلومات الرسم والصور النقطية للرسم عليها وتصميم الأنماط للرسم
للحصول على روابط إلى دروس تطبيقية أخرى حول الترميز في هذه الدورة التدريبية، اطّلِع على الصفحة المقصودة للإصدارات المتقدّمة من Android في لغة ترميز Kotlin.