وصف المدون

إعلان الرئيسية

دليل Widgets المتقدمة في Flutter: إتقان بناء واجهات المستخدم الاحترافية 2025

مقدمة: عالم Widgets المتقدمة في Flutter

في رحلة تعلم Flutter المتقدم، يأتي إتقان الـ Widgets كخطوة حاسمة لبناء تطبيقات احترافية ومتميزة. بعد فهم الأساسيات، حان الوقت للغوص عميقاً في عالم الـ Widgets المتقدمة التي تمكنك من إنشاء واجهات مستخدم معقدة وتفاعلية تنافس أفضل التطبيقات العالمية.

لماذا الـ Widgets المتقدمة؟ إن فهم الـ Widgets المتقدمة في Flutter يفتح أمامك إمكانيات لا محدودة لإنشاء تجارب مستخدم فريدة. من الرسوم المتحركة المعقدة إلى التخطيطات المتجاوبة والتفاعلات المتطورة، هذه الـ Widgets هي أدواتك لتحويل أفكارك الإبداعية إلى واقع رقمي مذهل.

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

StatelessWidget vs StatefulWidget: الفهم العميق

إن فهم الفرق بين StatelessWidget وStatefulWidget بعمق هو أساس بناء تطبيقات Flutter فعالة. هذا الفهم يتجاوز التعريفات البسيطة ليشمل متى وكيف نستخدم كل نوع لتحقيق أفضل أداء وتنظيم للكود.

StatelessWidget المتقدم:

import 'package:flutter/material.dart'; class AdvancedStatelessWidget extends StatelessWidget { final String title; final String subtitle; final IconData icon; final Color primaryColor; final VoidCallback? onTap; const AdvancedStatelessWidget({ Key? key, required this.title, required this.subtitle, required this.icon, this.primaryColor = Colors.blue, this.onTap, }) : super(key: key); @override Widget build(BuildContext context) { return Card( elevation: 8, margin: EdgeInsets.all(12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(16), child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), gradient: LinearGradient( colors: [ primaryColor.withOpacity(0.1), primaryColor.withOpacity(0.05), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Row( children: [ Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: primaryColor, borderRadius: BorderRadius.circular(12), ), child: Icon( icon, color: Colors.white, size: 24, ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 4), Text( subtitle, style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: primaryColor, size: 16, ), ], ), ), ), ); } }

StatefulWidget المتقدم مع إدارة حالة معقدة:

import 'package:flutter/material.dart'; class AdvancedCounter extends StatefulWidget { final int initialValue; final int minValue; final int maxValue; final Function(int)? onValueChanged; const AdvancedCounter({ Key? key, this.initialValue = 0, this.minValue = 0, this.maxValue = 100, this.onValueChanged, }) : super(key: key); @override _AdvancedCounterState createState() => _AdvancedCounterState(); } class _AdvancedCounterState extends State<AdvancedCounter> with TickerProviderStateMixin { late int _currentValue; late AnimationController _animationController; late Animation<double> _scaleAnimation; late Animation<Color?> _colorAnimation; @override void initState() { super.initState(); _currentValue = widget.initialValue; _animationController = AnimationController( duration: Duration(milliseconds: 200), vsync: this, ); _scaleAnimation = Tween<double>( begin: 1.0, end: 1.2, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.elasticOut, )); _colorAnimation = ColorTween( begin: Colors.blue, end: Colors.green, ).animate(_animationController); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _increment() { if (_currentValue < widget.maxValue) { setState(() { _currentValue++; }); _triggerAnimation(); widget.onValueChanged?.call(_currentValue); } } void _decrement() { if (_currentValue > widget.minValue) { setState(() { _currentValue--; }); _triggerAnimation(); widget.onValueChanged?.call(_currentValue); } } void _triggerAnimation() { _animationController.forward().then((_) { _animationController.reverse(); }); } @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 10, offset: Offset(0, 5), ), ], gradient: LinearGradient( colors: [Colors.white, Colors.grey[50]!], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( 'العداد المتقدم', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 20), AnimatedBuilder( animation: _animationController, builder: (context, child) { return Transform.scale( scale: _scaleAnimation.value, child: Container( width: 80, height: 80, decoration: BoxDecoration( color: _colorAnimation.value, shape: BoxShape.circle, ), child: Center( child: Text( '$_currentValue', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), ); }, ), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildControlButton( icon: Icons.remove, onPressed: _currentValue > widget.minValue ? _decrement : null, color: Colors.red, ), _buildControlButton( icon: Icons.add, onPressed: _currentValue < widget.maxValue ? _increment : null, color: Colors.green, ), ], ), SizedBox(height: 10), Text( 'النطاق: ${widget.minValue} - ${widget.maxValue}', style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), ); } Widget _buildControlButton({ required IconData icon, required VoidCallback? onPressed, required Color color, }) { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: color, shape: CircleBorder(), padding: EdgeInsets.all(16), elevation: 5, ), child: Icon( icon, color: Colors.white, size: 24, ), ); } }

نصيحة الأداء: استخدم StatelessWidget كلما أمكن لأنه أسرع في الأداء ويستهلك ذاكرة أقل. احتفظ بـ StatefulWidget للحالات التي تتطلب تحديث الواجهة فعلاً. هذا التوازن الصحيح يضمن أداءً مثالياً لتطبيقك.

دورة حياة الـ Widgets: الفهم العميق والتطبيق العملي

فهم دورة حياة الـ Widgets بعمق أمر بالغ الأهمية لبناء تطبيقات Flutter محسنة الأداء. كل مرحلة في دورة الحياة لها غرض محدد ويمكن استغلالها لتحسين تجربة المستخدم وأداء التطبيق.

دورة حياة StatefulWidget الكاملة:

import 'package:flutter/material.dart'; class LifecycleDemo extends StatefulWidget { final String title; const LifecycleDemo({Key? key, required this.title}) : super(key: key); @override _LifecycleDemoState createState() { print('🏗️ createState() - إنشاء الحالة'); return _LifecycleDemoState(); } } class _LifecycleDemoState extends State<LifecycleDemo> { int _counter = 0; late String _displayTitle; @override void initState() { super.initState(); print('🚀 initState() - تهيئة الحالة'); _displayTitle = widget.title; // تهيئة البيانات، الاشتراك في الأحداث، إعداد المؤقتات _initializeData(); } @override void didChangeDependencies() { super.didChangeDependencies(); print('🔄 didChangeDependencies() - تغيير التبعيات'); // يتم استدعاؤها عند تغيير التبعيات مثل Theme أو MediaQuery _updateBasedOnDependencies(); } @override void didUpdateWidget(LifecycleDemo oldWidget) { super.didUpdateWidget(oldWidget); print('🔄 didUpdateWidget() - تحديث الويدجت'); // مقارنة الخصائص الجديدة مع القديمة if (oldWidget.title != widget.title) { setState(() { _displayTitle = widget.title; }); } } @override Widget build(BuildContext context) { print('🎨 build() - بناء الواجهة'); return Scaffold( appBar: AppBar( title: Text(_displayTitle), backgroundColor: Colors.purple, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.purple.withOpacity(0.1), borderRadius: BorderRadius.circular(15), border: Border.all(color: Colors.purple, width: 2), ), child: Column( children: [ Text( 'دورة حياة الويدجت', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.purple, ), ), SizedBox(height: 10), Text( 'العداد: $_counter', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), ), ], ), ), SizedBox(height: 30), ElevatedButton( onPressed: _incrementCounter, style: ElevatedButton.styleFrom( backgroundColor: Colors.purple, padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25), ), ), child: Text( 'زيادة العداد', style: TextStyle(fontSize: 16, color: Colors.white), ), ), SizedBox(height: 20), Text( 'تحقق من وحدة التحكم لرؤية دورة الحياة', style: TextStyle( fontSize: 14, color: Colors.grey[600], fontStyle: FontStyle.italic, ), ), ], ), ), ); } @override void deactivate() { print('⏸️ deactivate() - إلغاء التفعيل'); super.deactivate(); } @override void dispose() { print('🗑️ dispose() - تنظيف الموارد'); // تنظيف الموارد: إلغاء الاشتراكات، إيقاف المؤقتات، تحرير الذاكرة _cleanupResources(); super.dispose(); } // دوال مساعدة void _initializeData() { // تهيئة البيانات الأولية print('📊 تهيئة البيانات...'); } void _updateBasedOnDependencies() { // تحديث البيانات بناءً على التبعيات print('🔗 تحديث التبعيات...'); } void _incrementCounter() { setState(() { _counter++; print('➕ تحديث العداد إلى: $_counter'); }); } void _cleanupResources() { // تنظيف الموارد print('🧹 تنظيف الموارد...'); } }

نصائح دورة الحياة: استخدم initState() لتهيئة البيانات التي لا تعتمد على context، وdidChangeDependencies() للبيانات التي تعتمد على context. تأكد من تنظيف جميع الموارد في dispose() لتجنب تسريب الذاكرة.

مراقبة دورة الحياة في الممارسة العملية:

class LifecycleMonitor extends StatefulWidget { @override _LifecycleMonitorState createState() => _LifecycleMonitorState(); } class _LifecycleMonitorState extends State<LifecycleMonitor> with WidgetsBindingObserver { List<String> _lifecycleEvents = []; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _addEvent('initState'); } @override void didChangeAppLifecycleState(AppLifecycleState state) { _addEvent('App State: ${state.toString()}'); switch (state) { case AppLifecycleState.resumed: _addEvent('التطبيق نشط'); break; case AppLifecycleState.inactive: _addEvent('التطبيق غير نشط'); break; case AppLifecycleState.paused: _addEvent('التطبيق متوقف مؤقتاً'); break; case AppLifecycleState.detached: _addEvent('التطبيق منفصل'); break; } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _addEvent('dispose'); super.dispose(); } void _addEvent(String event) { setState(() { _lifecycleEvents.add('${DateTime.now().toString().substring(11, 19)}: $event'); if (_lifecycleEvents.length > 10) { _lifecycleEvents.removeAt(0); } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('مراقب دورة الحياة'), backgroundColor: Colors.purple, ), body: Column( children: [ Container( padding: EdgeInsets.all(16), color: Colors.purple.withOpacity(0.1), child: Text( 'أحداث دورة الحياة الأخيرة:', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.purple, ), ), ), Expanded( child: ListView.builder( itemCount: _lifecycleEvents.length, itemBuilder: (context, index) { return Card( margin: EdgeInsets.symmetric(horizontal: 8, vertical: 2), child: ListTile( leading: CircleAvatar( backgroundColor: Colors.purple, child: Text('${index + 1}'), ), title: Text(_lifecycleEvents[index]), dense: true, ), ); }, ), ), ], ), ); } }

إنشاء Widgets مخصصة: من البسيط إلى المعقد

إنشاء Widgets مخصصة هو المفتاح لبناء تطبيقات منظمة وقابلة للصيانة. الـ Widgets المخصصة تسمح بإعادة الاستخدام وتنظيم الكود وإنشاء مكونات فريدة تميز تطبيقك عن غيره.

Widget مخصص بسيط - بطاقة معلومات:

import 'package:flutter/material.dart'; class InfoCard extends StatelessWidget { final String title; final String value; final IconData icon; final Color color; final String? subtitle; final VoidCallback? onTap; const InfoCard({ Key? key, required this.title, required this.value, required this.icon, this.color = Colors.blue, this.subtitle, this.onTap, }) : super(key: key); @override Widget build(BuildContext context) { return Card( elevation: 6, margin: EdgeInsets.all(8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(16), child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), gradient: LinearGradient( colors: [ color.withOpacity(0.1), Colors.white, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: EdgeInsets.all(10), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(10), ), child: Icon( icon, color: Colors.white, size: 20, ), ), SizedBox(width: 12), Expanded( child: Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.black87, ), ), ), ], ), SizedBox(height: 16), Text( value, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: color, ), ), if (subtitle != null) ...[ SizedBox(height: 4), Text( subtitle!, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ], ), ), ), ); } } // استخدام الـ Widget المخصص class InfoCardDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('بطاقات المعلومات المخصصة'), backgroundColor: Colors.purple, ), body: Padding( padding: EdgeInsets.all(16), child: GridView.count( crossAxisCount: 2, childAspectRatio: 1.2, children: [ InfoCard( title: 'المبيعات اليومية', value: '1,250 ر.س', icon: Icons.trending_up, color: Colors.green, subtitle: 'زيادة 12% عن أمس', onTap: () => print('تم النقر على المبيعات'), ), InfoCard( title: 'العملاء الجدد', value: '45', icon: Icons.people, color: Colors.blue, subtitle: 'هذا الأسبوع', ), InfoCard( title: 'الطلبات المعلقة', value: '8', icon: Icons.pending, color: Colors.orange, subtitle: 'تحتاج متابعة', ), InfoCard( title: 'التقييم العام', value: '4.8', icon: Icons.star, color: Colors.amber, subtitle: 'من 5 نجوم', ), ], ), ), ); } }

Widget معقد - مشغل موسيقى مخصص:

import 'package:flutter/material.dart'; class CustomMusicPlayer extends StatefulWidget { final String songTitle; final String artist; final String albumArt; final Duration duration; final Function(bool)? onPlayPause; final VoidCallback? onNext; final VoidCallback? onPrevious; const CustomMusicPlayer({ Key? key, required this.songTitle, required this.artist, required this.albumArt, required this.duration, this.onPlayPause, this.onNext, this.onPrevious, }) : super(key: key); @override _CustomMusicPlayerState createState() => _CustomMusicPlayerState(); } class _CustomMusicPlayerState extends State<CustomMusicPlayer> with TickerProviderStateMixin { bool _isPlaying = false; double _currentPosition = 0.0; late AnimationController _rotationController; late AnimationController _playButtonController; @override void initState() { super.initState(); _rotationController = AnimationController( duration: Duration(seconds: 10), vsync: this, ); _playButtonController = AnimationController( duration: Duration(milliseconds: 200), vsync: this, ); } @override void dispose() { _rotationController.dispose(); _playButtonController.dispose(); super.dispose(); } void _togglePlayPause() { setState(() { _isPlaying = !_isPlaying; }); if (_isPlaying) { _rotationController.repeat(); _playButtonController.forward(); } else { _rotationController.stop(); _playButtonController.reverse(); } widget.onPlayPause?.call(_isPlaying); } String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); String minutes = twoDigits(duration.inMinutes.remainder(60)); String seconds = twoDigits(duration.inSeconds.remainder(60)); return '$minutes:$seconds'; } @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(24), decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.purple.shade800, Colors.purple.shade600, Colors.pink.shade400, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.purple.withOpacity(0.3), blurRadius: 20, offset: Offset(0, 10), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Album Art with Rotation AnimatedBuilder( animation: _rotationController, builder: (context, child) { return Transform.rotate( angle: _rotationController.value * 2 * 3.14159, child: Container( width: 200, height: 200, decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 15, offset: Offset(0, 8), ), ], ), child: ClipOval( child: Image.network( widget.albumArt, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( color: Colors.grey[300], child: Icon( Icons.music_note, size: 80, color: Colors.grey[600], ), ); }, ), ), ), ); }, ), SizedBox(height: 32), // Song Info Text( widget.songTitle, style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, ), SizedBox(height: 8), Text( widget.artist, style: TextStyle( fontSize: 16, color: Colors.white.withOpacity(0.8), ), textAlign: TextAlign.center, ), SizedBox(height: 32), // Progress Bar Column( children: [ SliderTheme( data: SliderTheme.of(context).copyWith( activeTrackColor: Colors.white, inactiveTrackColor: Colors.white.withOpacity(0.3), thumbColor: Colors.white, overlayColor: Colors.white.withOpacity(0.2), thumbShape: RoundSliderThumbShape(enabledThumbRadius: 8), ), child: Slider( value: _currentPosition, max: widget.duration.inSeconds.toDouble(), onChanged: (value) { setState(() { _currentPosition = value; }); }, ), ), Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( _formatDuration(Duration(seconds: _currentPosition.toInt())), style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 12, ), ), Text( _formatDuration(widget.duration), style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 12, ), ), ], ), ), ], ), SizedBox(height: 24), // Control Buttons Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildControlButton( icon: Icons.skip_previous, onPressed: widget.onPrevious, size: 32, ), AnimatedBuilder( animation: _playButtonController, builder: (context, child) { return Transform.scale( scale: 1.0 + (_playButtonController.value * 0.1), child: Container( width: 64, height: 64, decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 8, offset: Offset(0, 4), ), ], ), child: IconButton( onPressed: _togglePlayPause, icon: AnimatedSwitcher( duration: Duration(milliseconds: 200), child: Icon( _isPlaying ? Icons.pause : Icons.play_arrow, key: ValueKey(_isPlaying), color: Colors.purple, size: 32, ), ), ), ), ); }, ), _buildControlButton( icon: Icons.skip_next, onPressed: widget.onNext, size: 32, ), ], ), ], ), ); } Widget _buildControlButton({ required IconData icon, required VoidCallback? onPressed, required double size, }) { return Container( width: 48, height: 48, decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), shape: BoxShape.circle, ), child: IconButton( onPressed: onPressed, icon: Icon( icon, color: Colors.white, size: size, ), ), ); } }

تقنيات متقدمة: في الـ Widget المعقد أعلاه، استخدمنا تقنيات متقدمة مثل AnimationController للرسوم المتحركة، وGradient للخلفيات المتدرجة، وCustom Shapes للأشكال المخصصة. هذه التقنيات تخلق تجربة مستخدم غنية ومتميزة.

Layout Widgets المتقدمة: إتقان التخطيطات المعقدة

إتقان Layout Widgets المتقدمة يمكنك من إنشاء تخطيطات معقدة ومتجاوبة تتكيف مع جميع أحجام الشاشات. هذه الـ Widgets هي أدواتك لتحويل التصاميم المعقدة إلى واقع قابل للتطبيق.

تخطيط متقدم باستخدام CustomScrollView:

import 'package:flutter/material.dart'; class AdvancedLayoutDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ // SliverAppBar المتقدم SliverAppBar( expandedHeight: 200, floating: false, pinned: true, flexibleSpace: FlexibleSpaceBar( title: Text( 'التخطيط المتقدم', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), background: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.purple.shade800, Colors.purple.shade400, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Center( child: Icon( Icons.dashboard, size: 80, color: Colors.white.withOpacity(0.3), ), ), ), ), ), // SliverPersistentHeader SliverPersistentHeader( pinned: true, delegate: _StickyHeaderDelegate( child: Container( color: Colors.white, padding: EdgeInsets.all(16), child: Row( children: [ Icon(Icons.filter_list, color: Colors.purple), SizedBox(width: 8), Text( 'الفئات', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.purple, ), ), ], ), ), ), ), // SliverGrid للشبكة SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.2, crossAxisSpacing: 10, mainAxisSpacing: 10, ), delegate: SliverChildBuilderDelegate( (context, index) { return Container( margin: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.purple.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.purple.shade200), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.category, size: 40, color: Colors.purple, ), SizedBox(height: 8), Text( 'فئة ${index + 1}', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.purple, ), ), ], ), ); }, childCount: 6, ), ), // SliverToBoxAdapter للمحتوى المخصص SliverToBoxAdapter( child: Container( margin: EdgeInsets.all(16), padding: EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue.shade50, Colors.purple.shade50], ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.2), blurRadius: 10, offset: Offset(0, 5), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'المحتوى المميز', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.purple, ), ), SizedBox(height: 10), Text( 'هذا مثال على استخدام SliverToBoxAdapter لإدراج محتوى مخصص في CustomScrollView.', style: TextStyle( fontSize: 16, color: Colors.grey[700], height: 1.5, ), ), ], ), ), ), // SliverList للقائمة SliverList( delegate: SliverChildBuilderDelegate( (context, index) { return Card( margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4), child: ListTile( leading: CircleAvatar( backgroundColor: Colors.purple, child: Text('${index + 1}'), ), title: Text('عنصر القائمة ${index + 1}'), subtitle: Text('وصف العنصر رقم ${index + 1}'), trailing: Icon(Icons.arrow_forward_ios), onTap: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('تم النقر على العنصر ${index + 1}'), ), ); }, ), ); }, childCount: 20, ), ), ], ), ); } } // مفوض الرأس الثابت class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate { final Widget child; _StickyHeaderDelegate({required this.child}); @override double get minExtent => 60; @override double get maxExtent => 60; @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { return child; } @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { return false; } }

تخطيط متجاوب باستخدام LayoutBuilder:

class ResponsiveLayout extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('التخطيط المتجاوب'), backgroundColor: Colors.purple, ), body: LayoutBuilder( builder: (context, constraints) { // تحديد نوع الجهاز بناءً على العرض if (constraints.maxWidth > 1200) { return _buildDesktopLayout(); } else if (constraints.maxWidth > 800) { return _buildTabletLayout(); } else { return _buildMobileLayout(); } }, ), ); } Widget _buildDesktopLayout() { return Row( children: [ // الشريط الجانبي Container( width: 250, color: Colors.purple.shade50, child: _buildSidebar(), ), // المحتوى الرئيسي Expanded( flex: 2, child: _buildMainContent(), ), // الشريط الجانبي الثانوي Container( width: 200, color: Colors.grey.shade50, child: _buildSecondarySidebar(), ), ], ); } Widget _buildTabletLayout() { return Row( children: [ // الشريط الجانبي المصغر Container( width: 80, color: Colors.purple.shade50, child: _buildCompactSidebar(), ), // المحتوى الرئيسي Expanded( child: _buildMainContent(), ), ], ); } Widget _buildMobileLayout() { return Column( children: [ // شريط التنقل العلوي Container( height: 60, color: Colors.purple.shade50, child: _buildTopNavigation(), ), // المحتوى الرئيسي Expanded( child: _buildMainContent(), ), ], ); } Widget _buildSidebar() { return ListView( padding: EdgeInsets.all(16), children: [ Text( 'القائمة الرئيسية', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.purple, ), ), SizedBox(height: 16), ...List.generate(5, (index) { return ListTile( leading: Icon(Icons.dashboard, color: Colors.purple), title: Text('عنصر ${index + 1}'), onTap: () {}, ); }), ], ); } Widget _buildCompactSidebar() { return ListView( padding: EdgeInsets.all(8), children: List.generate(5, (index) { return Padding( padding: EdgeInsets.symmetric(vertical: 8), child: IconButton( icon: Icon(Icons.dashboard, color: Colors.purple), onPressed: () {}, ), ); }), ); } Widget _buildTopNavigation() { return Row( children: [ IconButton( icon: Icon(Icons.menu, color: Colors.purple), onPressed: () {}, ), Expanded( child: Text( 'التنقل العلوي', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.purple, ), textAlign: TextAlign.center, ), ), IconButton( icon: Icon(Icons.search, color: Colors.purple), onPressed: () {}, ), ], ); } Widget _buildMainContent() { return Container( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'المحتوى الرئيسي', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black87, ), ), SizedBox(height: 16), Expanded( child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.5, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: 10, itemBuilder: (context, index) { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.2), blurRadius: 5, offset: Offset(0, 2), ), ], ), child: Center( child: Text( 'بطاقة ${index + 1}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ); }, ), ), ], ), ); } Widget _buildSecondarySidebar() { return Container( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'معلومات إضافية', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.grey[700], ), ), SizedBox(height: 16), ...List.generate(3, (index) { return Card( child: Padding( padding: EdgeInsets.all(12), child: Text('معلومة ${index + 1}'), ), ); }), ], ), ); } }

تحسين الأداء: استخدم LayoutBuilder بحكمة لتجنب إعادة البناء غير الضرورية. احرص على تخزين التخطيطات المعقدة في متغيرات منفصلة واستخدم const constructors كلما أمكن لتحسين الأداء.

Widgets التفاعلية: إنشاء تجارب مستخدم غنية

الـ Widgets التفاعلية هي قلب تجربة المستخدم في Flutter. هذه الـ Widgets تتيح للمستخدمين التفاعل مع التطبيق بطرق طبيعية ومباشرة، مما يخلق تجربة سلسة وممتعة.

Widget تفاعلي متقدم - لوحة التحكم:

import 'package:flutter/material.dart'; class InteractiveControlPanel extends StatefulWidget { @override _InteractiveControlPanelState createState() => _InteractiveControlPanelState(); } class _InteractiveControlPanelState extends State<InteractiveControlPanel> with TickerProviderStateMixin { double _brightness = 50.0; double _volume = 30.0; double _temperature = 22.0; bool _isWifiEnabled = true; bool _isBluetoothEnabled = false; bool _isLocationEnabled = true; late AnimationController _pulseController; late Animation<double> _pulseAnimation; @override void initState() { super.initState(); _pulseController = AnimationController( duration: Duration(seconds: 2), vsync: this, ); _pulseAnimation = Tween<double>(begin: 1.0, end: 1.1).animate( CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), ); _pulseController.repeat(reverse: true); } @override void dispose() { _pulseController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('لوحة التحكم التفاعلية'), backgroundColor: Colors.purple, elevation: 0, ), body: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.purple.shade50, Colors.blue.shade50, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( children: [ // قسم المتزلقات _buildSectionCard( title: 'التحكم في الإعدادات', icon: Icons.tune, children: [ _buildSliderControl( label: 'السطوع', value: _brightness, min: 0, max: 100, icon: Icons.brightness_6, color: Colors.orange, onChanged: (value) { setState(() { _brightness = value; }); }, ), _buildSliderControl( label: 'مستوى الصوت', value: _volume, min: 0, max: 100, icon: Icons.volume_up, color: Colors.blue, onChanged: (value) { setState(() { _volume = value; }); }, ), _buildSliderControl( label: 'درجة الحرارة', value: _temperature, min: 16, max: 30, icon: Icons.thermostat, color: Colors.red, suffix: '°C', onChanged: (value) { setState(() { _temperature = value; }); }, ), ], ), SizedBox(height: 16), // قسم المفاتيح _buildSectionCard( title: 'الاتصالات', icon: Icons.wifi, children: [ _buildSwitchControl( label: 'Wi-Fi', value: _isWifiEnabled, icon: Icons.wifi, activeColor: Colors.green, onChanged: (value) { setState(() { _isWifiEnabled = value; }); }, ), _buildSwitchControl( label: 'Bluetooth', value: _isBluetoothEnabled, icon: Icons.bluetooth, activeColor: Colors.blue, onChanged: (value) { setState(() { _isBluetoothEnabled = value; }); }, ), _buildSwitchControl( label: 'الموقع', value: _isLocationEnabled, icon: Icons.location_on, activeColor: Colors.purple, onChanged: (value) { setState(() { _isLocationEnabled = value; }); }, ), ], ), SizedBox(height: 16), // أزرار الإجراءات _buildSectionCard( title: 'إجراءات سريعة', icon: Icons.flash_on, children: [ Row( children: [ Expanded( child: _buildActionButton( label: 'إعادة تشغيل', icon: Icons.refresh, color: Colors.orange, onPressed: () => _showActionDialog('إعادة تشغيل'), ), ), SizedBox(width: 12), Expanded( child: AnimatedBuilder( animation: _pulseAnimation, builder: (context, child) { return Transform.scale( scale: _pulseAnimation.value, child: _buildActionButton( label: 'طوارئ', icon: Icons.warning, color: Colors.red, onPressed: () => _showActionDialog('طوارئ'), ), ); }, ), ), ], ), SizedBox(height: 12), Row( children: [ Expanded( child: _buildActionButton( label: 'حفظ الإعدادات', icon: Icons.save, color: Colors.green, onPressed: () => _saveSettings(), ), ), SizedBox(width: 12), Expanded( child: _buildActionButton( label: 'إعادة تعيين', icon: Icons.restore, color: Colors.grey, onPressed: () => _resetSettings(), ), ), ], ), ], ), ], ), ), ), ); } Widget _buildSectionCard({ required String title, required IconData icon, required List<Widget> children, }) { return Card( elevation: 8, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: Colors.purple, size: 24), SizedBox(width: 12), Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ], ), SizedBox(height: 16), ...children, ], ), ), ); } Widget _buildSliderControl({ required String label, required double value, required double min, required double max, required IconData icon, required Color color, String suffix = '', required ValueChanged<double> onChanged, }) { return Padding( padding: EdgeInsets.symmetric(vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: color, size: 20), SizedBox(width: 8), Text( label, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, ), ), Spacer(), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( '${value.round()}$suffix', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: color, ), ), ), ], ), SliderTheme( data: SliderTheme.of(context).copyWith( activeTrackColor: color, inactiveTrackColor: color.withOpacity(0.3), thumbColor: color, overlayColor: color.withOpacity(0.2), ), child: Slider( value: value, min: min, max: max, onChanged: onChanged, ), ), ], ), ); } Widget _buildSwitchControl({ required String label, required bool value, required IconData icon, required Color activeColor, required ValueChanged<bool> onChanged, }) { return Padding( padding: EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Icon( icon, color: value ? activeColor : Colors.grey, size: 20, ), SizedBox(width: 12), Expanded( child: Text( label, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, ), ), ), Switch( value: value, onChanged: onChanged, activeColor: activeColor, ), ], ), ); } Widget _buildActionButton({ required String label, required IconData icon, required Color color, required VoidCallback onPressed, }) { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: color, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 4, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 24), SizedBox(height: 4), Text( label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, ), ), ], ), ); } void _showActionDialog(String action) { showDialog( context: context, builder: (context) => AlertDialog( title: Text('تأكيد الإجراء'), content: Text('هل أنت متأكد من تنفيذ إجراء "$action"؟'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('إلغاء'), ), ElevatedButton( onPressed: () { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('تم تنفيذ إجراء $action')), ); }, child: Text('تأكيد'), ), ], ), ); } void _saveSettings() { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('تم حفظ الإعدادات بنجاح'), backgroundColor: Colors.green, ), ); } void _resetSettings() { setState(() { _brightness = 50.0; _volume = 30.0; _temperature = 22.0; _isWifiEnabled = true; _isBluetoothEnabled = false; _isLocationEnabled = true; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('تم إعادة تعيين الإعدادات'), backgroundColor: Colors.orange, ), ); } }

تفاعل متقدم: في المثال أعلاه، استخدمنا تقنيات متقدمة مثل AnimationController للرسوم المتحركة، وSliderTheme لتخصيص المتزلقات، وShowDialog للحوارات التفاعلية. هذه التقنيات تخلق تجربة تفاعلية غنية ومتجاوبة.

أفضل الممارسات المتقدمة في Widgets

تطبيق أفضل الممارسات المتقدمة في تطوير الـ Widgets يضمن إنشاء تطبيقات عالية الأداء وسهلة الصيانة. هذه الممارسات مستمدة من خبرات المطورين المحترفين والتوصيات الرسمية من فريق Flutter.

جدول مقارنة أنواع الـ Widgets:

نوع الـ Widget الاستخدام الأمثل الأداء إدارة الحالة
StatelessWidget المحتوى الثابت عالي جداً لا يحتاج
StatefulWidget المحتوى المتغير جيد مدمج
InheritedWidget مشاركة البيانات متوسط متقدم
Provider إدارة الحالة العامة جيد جداً احترافي

نصائح الأداء المتقدمة:

  • استخدم const constructors: كلما أمكن لتجنب إعادة البناء غير الضرورية
  • فصل الـ Widgets: قسم الـ Widgets الكبيرة إلى مكونات أصغر
  • تجنب الدوال في build(): لا تنشئ widgets جديدة داخل build method
  • استخدم ListView.builder: للقوائم الطويلة بدلاً من Column مع children
  • تحسين الصور: استخدم أحجام مناسبة وتنسيقات محسنة

مثال على أفضل الممارسات:

// ❌ ممارسة خاطئة class BadPracticeWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: [ // إنشاء widget جديد في كل build Container( padding: EdgeInsets.all(16), child: Text('عنوان'), ), // استخدام دالة داخل build _buildComplexWidget(), ], ); } Widget _buildComplexWidget() { return Container(/* ... */); } } // ✅ ممارسة صحيحة class GoodPracticeWidget extends StatelessWidget { // إنشاء widgets ثابتة خارج build static const Widget _titleWidget = Padding( padding: EdgeInsets.all(16), child: Text('عنوان'), ); @override Widget build(BuildContext context) { return Column( children: [ _titleWidget, const ComplexWidget(), // widget منفصل ], ); } } class ComplexWidget extends StatelessWidget { const ComplexWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(16), decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(8)), ), child: const Text('محتوى معقد'), ); } }

نصيحة متقدمة: استخدم Flutter Inspector وPerformance Overlay لمراقبة أداء تطبيقك. هذه الأدوات تساعدك في تحديد الـ Widgets التي تحتاج تحسين وتتبع استهلاك الذاكرة والمعالج.

خاتمة: إتقان فن الـ Widgets في Flutter

إن إتقان Widgets المتقدمة في Flutter يفتح أمامك عالماً من الإمكانيات اللامحدودة لإنشاء تطبيقات استثنائية. من خلال فهم دورة الحياة وإنشاء مكونات مخصصة وتطبيق أفضل الممارسات، تصبح قادراً على بناء تجارب مستخدم لا تُنسى.

رحلة التعلم المستمرة: عالم Flutter يتطور باستمرار، وكذلك يجب أن تكون مهاراتك. استمر في التجريب والتعلم، وشارك في المجتمع العربي لمطوري Flutter. كل widget تتقنه يقربك خطوة من أن تصبح خبيراً في تطوير التطبيقات الاحترافية.

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


إقرأ أيضا هذا المقال التفصيلي حول تعلم Flutter وDart بالعربية للمبتدئين: دليلك الشامل لتطوير التطبيقات 2025

ليست هناك تعليقات
إرسال تعليق

إعلان أول الموضوع

إعلان وسط الموضوع

إعلان أخر الموضوع

Back to top button