
أنا أحب Dribbble . هناك العديد من مشاريع التصميم الرائعة والملهمة. ولكن إذا كنت مطورًا ، فغالبًا ما يتم استبدال الشعور بالجمال سريعًا باليأس عندما تبدأ التفكير في كيفية تنفيذ هذا التصميم الرائع.
في هذه المقالة سأريك مثالاً على هذا التصميم وتنفيذه ، لكن قبل ذلك ، دعونا نتحدث عن حل المشكلة ككل.
أسهل طريقة هي استخدام نوع من المكتبات التي تغطي احتياجاتنا. الآن لا تفهموني خطأ ، أنا مؤيد كبير لنهج "عدم اختراع العجلة". هناك مكتبات كبيرة مفتوحة المصدر ، وعندما أحتاج إلى تحميل الصور أو تطبيق REST API ، سوف يساعدني Glide / Picasso و Retrofit كثيرًا.
ولكن عندما تحتاج إلى تنفيذ بعض التصميمات غير العادية ، فليس هذا هو الخيار الأفضل دائمًا. ستحتاج إلى قضاء بعض الوقت في البحث عن مكتبة جيدة ومدعومة ستقوم بعمل مشابه. ثم تحتاج إلى البحث في الكود للتأكد من أن هناك شيئًا ما مكتوبًا هناك. ستحتاج إلى تخصيص مزيد من الوقت لفهم الإعدادات والتكوينات التي يمكنك إدارتها لاستخدام المكتبة في مهامك. ودعونا نكون صادقين ، على الأرجح ، لن تغطي المكتبة احتياجاتك بنسبة 100 ٪ ، وسوف تحتاج إلى تقديم بعض التنازلات مع المصممين.
لذلك ، أقول إنه غالبًا ما يكون من الأسهل والأفضل إنشاء مكون View
الخاص بك. عندما أقول "مكون View
الأصلي" ، أقصد امتداد فئة View
، onDraw()
طريقة onDraw()
واستخدام Paint
Canvas
لرسم مكون View
. قد يبدو هذا مخيفًا إذا لم تكن قد فعلت ذلك من قبل ، لأن هذه الفئات بها العديد من الأساليب والخصائص ، لكن يمكنك التركيز على الخصائص الرئيسية:
canvas.drawRect()
- تحديد إحداثيات الزوايا ورسم مستطيل ؛
canvas.drawRoundRect()
- حدد نصف القطر اختياريًا ، وسيتم تقريب زوايا المستطيل ؛
canvas.drawPath()
هي طريقة أكثر تعقيدًا ، لكنها أيضًا أكثر قوة لإنشاء الشكل الخاص بك باستخدام الخطوط والمنحنيات ؛
canvas.drawText()
- لرسم النص على قماش (باستخدام Paint
يمكنك التحكم في الحجم واللون والخصائص الأخرى) ؛
canvas.drawCircle()
- حدد نقطة الوسط ونصف القطر واحصل على دائرة ؛
canvas.drawArc()
- حدد المستطيل المحيط ، وكذلك canvas.drawArc()
لرسم القوس ؛
paint.style
- يشير إلى ما إذا كان الشكل المرسوم سوف يتم ملؤه ، دائري ، أو كلاهما ؛
paint.color
- يشير إلى اللون (بما في ذلك الشفافية) ؛
paint.strokeWidth
- يتحكم في عرض أشكال الحد ؛
paint.pathEffect
- يسمح لك بالتأثير على هندسة الشكل المرسوم ؛
paint.shader
- يسمح لك برسم التدرجات.
تذكر ، في بعض الأحيان قد تحتاج إلى استخدام واجهات برمجة التطبيقات الأخرى ، ولكن حتى بعد إتقان هذه الأساليب ، يمكنك رسم أشكال معقدة للغاية.
مثال عملي
هنا تصميم الفلفل يقدم لنا:

هناك العديد من الأشياء المثيرة للاهتمام هنا ، ولكن دعونا نأخذ كل شيء إلى قطع صغيرة.
الخطوة 1. حساب المواقف علامة
private fun calcPositions(markers: List<Marker>) { val max = markers.maxBy { it.value } val min = markers.minBy { it.value } pxPerUnit = chartHeight / (max - min) zeroY = max * pxPerUnit + paddingTop val step = (width - 2 * padding - scalesWidth) / (markers.size - 1) for ((i, marker) in markers.withIndex()) { val x = step * i + paddingLeft val y = zeroY - entry.value * pxPerUnit marker.currentPos.x = x marker.currentPos.y = y } }
نجد الحد الأدنى والحد الأقصى للقيم ، ونحسب نسبة البكسل لكل وحدة ، وحجم الخطوة الأفقية بين العلامات والمواقع X و Y.
الخطوة 2. رسم التدرج

نقوم بإنشاء شكل يبدأ من الحافة اليسرى ، ويرسم خطًا بين كل علامة وينهي الشكل عند نقطة البداية. ثم ارسم هذا الشكل باستخدام الطلاء مع تظليل التدرج.
الخطوة 3. ارسم شبكة

نحن تخصيص الطلاء بحيث شرطات. ثم نستخدم دورة لغة Kotlin الخاصة ، والتي تسمح لنا بالتكرار على العلامات في الخطوات من 7 (عدد الأيام في الأسبوع). لكل علامة ، نأخذ إحداثي X zeroY
خطًا منقط رأسياً من أعلى الرسم البياني إلى zeroY
.
الخطوة 4. رسم الرسم البياني وعلامات

private fun drawLineAndMarkers(canvas: Canvas) { var previousMarker: Marker? = null for (marker in markers) { if (previousMarker != null) {
نذهب إلى العلامات ونرسم دائرة مليئة بكل منها وخط بسيط من العلامة السابقة إلى الحالية.
الخطوة 5. رسم أزرار الأسابيع

private fun drawWeeks(canvas: Canvas) { for ((i, week) in weeks.withIndex()) { textPaint.getTextBounds(week, 0, week.length, rect) val x = middle(i) val y = zeroY + rect.height() val halfWidth = rect.width() / 2f val halfHeight = rect.height() / 2f val left = x - halfWidth - padding val top = y - halfHeight - padding val right = x + halfWidth + padding val bottom = y + halfHeight + padding rect.set(left, top, right, bottom) paint.color = bgColor paint.style = FILL canvas.drawRoundRect(rect, radius, radius, paint) paint.color = strokeColor paint.style = STROKE canvas.drawRoundRect(rect, radius, radius, paint) canvas.drawText(week, x, keyY, textPaint) } }
نذهب فوق علامات الأسبوع ونجد إحداثي X في منتصف الأسبوع ونبدأ في رسم الزر في طبقات: أولاً نرسم خلفية بزوايا مستديرة ، ثم نضع حدًا وأخيراً نصًا. نقوم بضبط الطلاء قبل رسم كل طبقة.
الخطوة 6. ارسم العلامات الرقمية على اليمين

private fun drawGraduations(canvas: Canvas) { val x = markers.last().currentPos.x + padding for (value in graduations) { val y = zeroY - scale * pxPerUnit val formatted = NumberFormat.getIntegerInstance().format(value) canvas.drawText(formatted, x, y, textPaint) } }
إحداثي X هو موضع العلامة الأخيرة بالإضافة إلى بعض المسافة البادئة. يتم حساب إحداثي Y باستخدام نسبة البكسل لكل وحدة. نقوم بتنسيق الرقم في سلسلة (إذا لزم الأمر ، أضف فاصل الآلاف) ورسم النص.
هذا كل شيء ، الآن سيبدو onDraw()
كما يلي:
override fun onDraw(canvas: Canvas) { drawGradient(canvas) drawGuidelines(canvas) drawLineAndMarkers(canvas) drawWeeks(canvas) drawGraduations(canvas) }
والجمع بين الطبقات يعطينا النتيجة المرجوة:

ملخص
- لا تخف من إنشاء مكونات
View
خاصة بك (إذا لزم الأمر). - تعلم واجهات برمجة التطبيقات
Canvas
and Paint
الأساسية. - قسم التصميم الخاص بك إلى طبقات صغيرة وارسم كل منها بشكل مستقل.
بالنسبة للنقطة الأخيرة ، بالنسبة لي ، يعد هذا أحد أفضل دروس البرمجة بشكل عام: عند مواجهة مهمة كبيرة ومعقدة ، قسّمها إلى مهام أصغر وأكثر بساطة.