الظلال والتمويه وتأثيرات الطبقات
الظلال والتمويه وتأثيرات الطبقات في Flutter Canvas
توفر واجهة برمجة التطبيقات Canvas في Flutter ثلاثة عناصر أساسية قوية للعمق والثراء البصري: الظلال المسقطة عبر canvas.drawShadow، وتأثيرات التمويه عبر Paint.maskFilter، وتركيب الطبقات عبر canvas.saveLayer مع BlendMode. إتقان هذه الأدوات يتيح لك محاكاة ظلال الصندوق المشابهة لـ CSS، وطبقات الضبابية الزجاجية، وأوضاع المزج المتقدمة بالكامل في Dart.
رسم الظلال المسقطة باستخدام canvas.drawShadow
تُقدِّم Canvas.drawShadow ظلاً لأي Path. هي محسَّنة للغاية — إذ يفوّض المحرك إلى العمليات الأولية لإسقاط الظل في Skia، مما يجعلها أسرع من رسم شكل ضبابي يدوياً.
مثال أساسي على الظل المسقط
import 'package:flutter/material.dart';
class ShadowPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final path = Path()
..addRRect(
RRect.fromRectAndRadius(
Rect.fromLTWH(40, 40, size.width - 80, size.height - 80),
const Radius.circular(16),
),
);
// drawShadow(path, color, elevation, transparentOccluder)
canvas.drawShadow(path, Colors.black87, 8.0, false);
// ارسم البطاقة فوق الظل
final paint = Paint()..color = Colors.white;
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
المعاملات الأربعة لـ drawShadow هي:
- path — الشكل الذي يُلقي الظل من خلال صورته الظلية.
- color — لون الظل (يُحترم قيمة الشفافية alpha).
- elevation — ارتفاع Z الافتراضي بأسلوب Material بالبكسل المنطقي؛ القيم الأعلى تمدد الظل أكثر.
- transparentOccluder — اضبطه على
trueعندما يكون الشكل نفسه شفافاً جزئياً حتى لا يُقنَّع الظل بالشكل.
canvas.drawShadow فقط Path. لإضافة ظل لصورة أو ودجت عشوائي، استخدم زخرفة BoxShadow أو تقنية saveLayer + التمويه الموضحة أدناه.تطبيق تأثيرات التمويه باستخدام MaskFilter
ضبط paint.maskFilter على MaskFilter.blur يطبّق تمويهاً غاوسياً على كل ما يرسمه Paint. هذه هي الطريقة الصحيحة لإنتاج توهجات ناعمة، وتأثيرات الضباب، والظلال الضبابية.
تأثير التوهج بالتمويه الغاوسي
class GlowPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
const radius = 60.0;
// 1. ارسم حلقة توهج ضبابية خلف الدائرة
final glowPaint = Paint()
..color = Colors.cyanAccent.withOpacity(0.6)
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 20.0);
canvas.drawCircle(center, radius + 10, glowPaint);
// 2. ارسم الدائرة الصلبة الحادة فوقها
final solidPaint = Paint()..color = Colors.cyan;
canvas.drawCircle(center, radius, solidPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
يأخذ MaskFilter.blur معاملين:
- BlurStyle —
normal(يموّه الداخل والخارج)،inner(الداخل فقط)،outer(الخارج فقط)،solid(حافة صلبة مع تمويه خارجي). - sigma — الانحراف المعياري للنواة الغاوسية بالبكسل المنطقي. القيم الأكبر تنتج تمويهاً أكثر نعومة وانتشاراً.
sigma في كل إطار على مسارات معقدة. قم بالعرض المسبق للطبقات الضبابية إلى Picture، أو استخدم ImageFilter.blur عبر ودجت BackdropFilter لتمويهات أرخص في الوقت الفعلي.تركيب الطبقات باستخدام canvas.saveLayer و BlendMode
تدفع canvas.saveLayer(bounds, paint) صورة نقطية خارج الشاشة (طبقة تركيب) إلى مكدس اللوحة. جميع استدعاءات الرسم اللاحقة تُرسم على تلك الطبقة خارج الشاشة. عند استدعاء canvas.restore()، تُركَّب الطبقة على اللوحة الرئيسية باستخدام BlendMode والشفافية المحددين في Paint الخاصة بالطبقة.
saveLayer مع BlendMode.multiply
class LayerBlendPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final rect = Offset.zero & size;
// ارسم الطبقة الأساسية — خلفية متدرجة
final bgPaint = Paint()
..shader = LinearGradient(
colors: [Colors.orange, Colors.deepPurple],
).createShader(rect);
canvas.drawRect(rect, bgPaint);
// افتح طبقة تركيب جديدة مع BlendMode.multiply
final layerPaint = Paint()..blendMode = BlendMode.multiply;
canvas.saveLayer(rect, layerPaint);
// أي شيء يُرسم هنا يُركَّب بوضع multiply
final circlePaint = Paint()..color = Colors.lightBlueAccent;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
size.width * 0.35,
circlePaint,
);
// الاستعادة: تُمزج الدائرة على التدرج بوضع multiply
canvas.restore();
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
قيم BlendMode الرئيسية لتأثيرات الطبقات:
- BlendMode.multiply — يضرب ألوان المصدر والوجهة؛ يُقتِّم الألوان.
- BlendMode.screen — ضرب معكوس؛ يُفتِّح الألوان.
- BlendMode.overlay — multiply أو screen بناءً على سطوع الوجهة.
- BlendMode.dstIn — يقصّ الوجهة على ألفا المصدر؛ رائع لقصاصات الأقنعة.
- BlendMode.luminosity — يطبّق سطوع المصدر على درجة لون الوجهة وتشبعها.
saveLayer يخصص نسيجاً خارج الشاشة. يمكن أن يؤثر تداخل استدعاءات saveLayer المتعددة (خاصة داخل الحركات) تأثيراً بالغاً على الأداء. استدعِ دائماً canvas.restore() لكل saveLayer، وفضِّل canvas.save() (بدون نسيج خارج الشاشة) عندما تحتاج فقط لعزل التحويلات أو القصاصات.الجمع بين الثلاث تقنيات
غالباً ما يجمع الرسامون المخصصون في العالم الحقيقي بين الظلال والتمويه وتأثيرات الطبقات. النمط الشائع هو رسم ظل شفاف ضبابي باستخدام saveLayer + MaskFilter، ثم رسم الشكل الأمامي الحاد فوقه مع drawShadow للعمق المحيطي.
ملخص
في هذا الدرس تعلمت:
canvas.drawShadow(path, color, elevation, transparentOccluder)— ظل سريع وواعٍ لارتفاع Material لأيPath.paint.maskFilter = MaskFilter.blur(style, sigma)— تمويه غاوسي مطبَّق على مخرجاتPaint، يتيح التوهجات والظلال الناعمة.canvas.saveLayer(bounds, paint)+canvas.restore()— يركِّب طبقة خارج الشاشة على اللوحة باستخدامBlendMode، مما يتيح تأثيرات multiply وscreen وoverlay وقناع الألفا.- اعتبارات الأداء: قلِّل تداخل
saveLayerوتجنب إعادة التمويه في كل إطار دون ضرورة.