الودجات المخصصة والرسم المخصص

التدرجات اللونية والظلال على اللوحة

16 دقيقة الدرس 6 من 12

التدرجات اللونية والظلال على اللوحة

توفر واجهة برمجة CustomPainter في Flutter وصولاً مباشراً إلى كائن Canvas، حيث يمكنك التحكم الكامل في كل بكسل. ومن أكثر التقنيات تأثيراً بصرياً المتاحة هي تطبيق ظلال التدرج على كائن Paint. بدلاً من ملء الأشكال بلون مسطح، تُرفق Shader ناتجة عن تدرج، ويقوم المعالج الرسومي (GPU) بإيجاد انتقال سلس للألوان عبر المنطقة المرسومة.

تكشف مكتبة dart:ui في Dart عن ثلاث فئات للتدرجات: Gradient.linear وGradient.radial وGradient.sweep. كل منها تُعيد Shader تُسندها إلى Paint.shader. عندما ترسم مستطيلاً أو دائرة أو مساراً أو أي شكل آخر بهذا الطلاء، يحدد الظل لون كل نقطة.

ملاحظة: يُعرَّف Shader في إحداثيات اللوحة المحلية. إذا قمت بترجمة اللوحة أو تحجيمها أو تدويرها قبل الرسم، فإن إحداثيات الظل تتحرك مع تحويل اللوحة. ضع هذا في اعتبارك عند محاذاة التدرجات مع مناطق محددة من الشاشة.

ظل التدرج الخطي (LinearGradient)

يمزج التدرج الخطي الألوان على طول خط مستقيم يُحدَّد بنقطتين. تُحدد نقطة البداية ونقطة النهاية وقائمة الألوان ومواضع التوقف الاختيارية. تتحكم المعامِلة tileMode في ما يحدث خارج نقاط نهاية التدرج.

تطبيق LinearGradient على مستطيل

class LinearGradientPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final rect = Offset.zero & size;

    final shader = const LinearGradient(
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [Color(0xFF6A11CB), Color(0xFF2575FC)],
    ).createShader(rect);

    final paint = Paint()..shader = shader;
    canvas.drawRect(rect, paint);

    // رسم مستطيل ذو حواف مدورة بنفس التدرج
    final rrect = RRect.fromRectAndRadius(
      rect.deflate(24),
      const Radius.circular(16),
    );
    canvas.drawRRect(rrect, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
نصيحة: Offset.zero & size هو اختصار لـ Rect.fromLTWH(0, 0, size.width, size.height). تمرير هذا المستطيل إلى createShader يثبّت التدرج بدقة داخل منطقة الرسم.

ظل التدرج الشعاعي (RadialGradient)

يشع التدرج الشعاعي للخارج من نقطة مركزية بؤرية. يمكنك التحكم في المركز ونصف القطر ونقطة البؤرة الاختيارية وقائمة الألوان ومواضع التوقف. تُنتج نقطة البؤرة المختلفة عن المركز تشويهاً شبيهاً بالمخروط مفيداً في تأثيرات وهج العدسة.

RadialGradient لدائرة متوهجة

class RadialGradientPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.shortestSide / 2;
    final rect = Rect.fromCircle(center: center, radius: radius);

    final shader = const RadialGradient(
      center: Alignment.center,
      radius: 1.0,
      colors: [
        Color(0xFFFFE259),
        Color(0xFFFFA751),
        Color(0xFF00000000),
      ],
      stops: [0.0, 0.6, 1.0],
    ).createShader(rect);

    final paint = Paint()..shader = shader;
    canvas.drawCircle(center, radius, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

ظل التدرج الدوراني (SweepGradient)

يدور التدرج الدوراني حول نقطة مركزية كعقارب الساعة، ينتقل من startAngle إلى endAngle (بالراديان). يُعدّ مثالياً للمقاييس القوسية وعجلات الألوان ومؤشرات الحلقات.

SweepGradient على قوس / عجلة ألوان

import 'dart:math' as math;

class SweepGradientPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.shortestSide / 2 - 8;
    final rect = Rect.fromCircle(center: center, radius: radius);

    final shader = SweepGradient(
      center: Alignment.center,
      startAngle: 0.0,
      endAngle: math.pi * 2,
      colors: const [
        Color(0xFFFF0000),
        Color(0xFFFFFF00),
        Color(0xFF00FF00),
        Color(0xFF00FFFF),
        Color(0xFF0000FF),
        Color(0xFFFF00FF),
        Color(0xFFFF0000),
      ],
    ).createShader(rect);

    final paint = Paint()
      ..shader = shader
      ..style = PaintingStyle.stroke
      ..strokeWidth = 16;

    canvas.drawCircle(center, radius, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
تحذير: تستخدم createShader(rect) المستطيل المُمرَّر لتعيين إحداثيات التدرج في فضاء اللوحة. إذا كان المستطيل الذي تمرره لا يتطابق مع الشكل الذي ترسمه، سيبدو التدرج غير محاذٍ. احرص دائماً على اشتقاق مستطيل الظل من نفس الحدود التي تنوي رسمها.

TileMode: التحكم في تكرار التدرج

تقبل الأنواع الثلاثة للتدرجات معامِلة tileMode التي تتحكم في سلوك التدرج خارج حدوده المُعرَّفة:

  • TileMode.clamp (الافتراضي) — يمدد لون الحافة إلى الخارج بلا حدود.
  • TileMode.repeated — يبلّط التدرج بسلاسة مُنتجاً تأثيراً مخططاً.
  • TileMode.mirror — يعكس التدرج بالتناوب لتبليط أملس.
  • TileMode.decal — يُظهر الشفافية خارج منطقة التدرج (Flutter 3 وما فوق).

دمج ظلال متعددة بالطبقات

لا تمتلك اللوحة واجهة برمجية مدمجة لـ "ضرب الظلال"، لكن يمكنك تراكب التأثيرات بحفظ واسترداد طبقات اللوحة عبر canvas.saveLayer وأوضاع المزج. من الأنماط الشائعة رسم قاعدة تدرجية ثم تراكب طلاء ثانٍ بـ BlendMode.multiply أو BlendMode.overlay للحصول على عمق لوني غني.

خلاصة

ترفع ظلال التدرج الرسم المخصص من تعبئة مسطحة إلى انتقالات لونية مُسرَّعة بالمعالج الرسومي. سير العمل الرئيسي هو: إنشاء كائن التدرج ← استدعاء createShader(rect) ← إسناد النتيجة إلى Paint.shader ← رسم الأشكال بهذا الطلاء. استخدم LinearGradient للانتقالات الاتجاهية، وRadialGradient للأضواء الدائرية ونقاط الإضاءة، وSweepGradient للأقواس الدورانية وعجلات الألوان. احرص دائماً على محاذاة مستطيل الظل مع المنطقة المرسومة، واستفد من TileMode للتحكم في سلوك الحواف.