Flutter Dev Fundamentals: Part 1 – Structure, Widgets & WTF Moments in Flutter
Teqani Blogs
Writer at Teqani
Flutter is fun… until it’s not. This article, Part 1 of a series, helps intermediate developers structure their Flutter projects, avoid widget layering traps, and understand basic state management. It’s a no-BS guide to solving real-world Flutter pain points.
فلاتر ممتعة... حتى لا تكون كذلك. تساعد هذه المقالة، وهي الجزء الأول من سلسلة، المطورين المتوسطين على هيكلة مشاريع فلاتر الخاصة بهم، وتجنب مصائد طبقات الأدوات، وفهم إدارة الحالة الأساسية. إنه دليل خالٍ من الهراء لحل نقاط الألم الواقعية في فلاتر.
📁 Ideal Project Structure (aka Stop Throwing Everything in main.dart)
When your app grows beyond 3–4 screens, you need structure. Otherwise, you’re scrolling through a 600-line widget tree with zero idea where anything lives.
عندما يتجاوز تطبيقك 3-4 شاشات، فأنت بحاجة إلى هيكل. بخلاف ذلك، فأنت تتصفح شجرة أدوات مكونة من 600 سطر مع عدم وجود فكرة عن مكان وجود أي شيء.
Here’s a simple, scalable layout that actually works:
إليك تخطيط بسيط وقابل للتطوير يعمل بالفعل:
- lib/
- │
- ├── main.dart
- ├── core/ # common utils, themes, constants
- │ ├── theme/
- │ ├── router.dart
- │ └── widgets/ # shared custom widgets
- │
- ├── features/ # modular feature folders
- │ ├── auth/
- │ │ ├── data/
- │ │ ├── domain/
- │ │ └── presentation/
- │ │ ├── login_screen.dart
- │ │ └── widgets/
- │
- └── services/ # external services, API, storage
🎯 Tip: Treat every major feature (Auth, Home, Profile, etc.) as a mini app — this helps you scale and test easily.
🎯 نصيحة: تعامل مع كل ميزة رئيسية (المصادقة، الصفحة الرئيسية، الملف الشخصي، إلخ) كتطبيق صغير - يساعدك ذلك على التوسع والاختبار بسهولة.
🤯 Widget Layering Traps (a.k.a “Why the hell is this overflowing again?”)
So, you wrapped a Column with Expanded, then added a ListView, then your app started shaking and screaming. We’ve all been there.
لذا، قمت بلف عمود بـ موسع، ثم أضفت قائمة عرض، ثم بدأ تطبيقك يهتز ويصرخ. لقد مررنا جميعًا بذلك.
🧠 Mental Model Fix: Column + ListView = often broken unless you manage height properly. Expanded expects to live inside a Flex widget (like Row or Column). ListView already scrolls — don’t put it inside another scroll view unless you know how to constrain it.
🧠 إصلاح النموذج العقلي: العمود + قائمة العرض = غالبًا ما تكون مكسورة ما لم تقم بإدارة الارتفاع بشكل صحيح. يتوقع الموسع أن يعيش داخل أداة Flex (مثل الصف أو العمود). تقوم قائمة العرض بالفعل بالتمرير - لا تضعها داخل طريقة عرض تمرير أخرى ما لم تكن تعرف كيفية تقييدها.
❌ Bad Example:
❌ مثال سيء:
Expanded(
child: Column(
children: [
Text("Header"),
ListView( // 💥 Boom. Layout overflow.
children: [...]
),
],
),
)
✅ Better Approach:
✅ نهج أفضل:
Column(
children: [
Text("Header"),
Expanded(
child: ListView(
children: [...],
),
),
],
)
🧩 Things I Wish I Knew Earlier: You can’t just slap Expanded or Flexible anywhere. Think of them as space negotiators — they need context to know how much they’re allowed to grow.
🧩 أشياء تمنيت لو عرفتها سابقًا: لا يمكنك ببساطة وضع Expanded أو Flexible في أي مكان. فكر فيهم على أنهم مفاوضون على المساحة - إنهم بحاجة إلى سياق لمعرفة مقدار النمو المسموح لهم به.
🧠 State Management 101: When to Use setState, When to Not
If your widget tree is small and you’re not sharing state across multiple widgets — setState is perfect. It’s fast, easy, and native.
إذا كانت شجرة الأدوات الخاصة بك صغيرة ولا تشارك الحالة عبر أدوات متعددة - فإن setState مثالية. إنها سريعة وسهلة وأصلية.
✅ Use setState when:
✅ استخدم setState عندما:
- You’re dealing with local state, like toggling a switch, showing a dialog, or handling form input.
- The widget rebuilding is contained and doesn’t affect siblings or parents.
- أنت تتعامل مع الحالة المحلية، مثل تبديل مفتاح، أو إظهار مربع حوار، أو معالجة إدخال النموذج.
- إعادة بناء الأدوات محتوية ولا تؤثر على الأشقاء أو الآباء.
bool isVisible = false;
ElevatedButton(
onPressed: () {
setState(() {
isVisible = !isVisible;
});
},
child: Text("Toggle"),
)
❌ Don’t use setState when:
❌ لا تستخدم setState عندما:
- Multiple widgets need the same state (e.g., a user object used in navbar + home + profile).
- You want separation of concerns (e.g., business logic shouldn’t live inside UI).
- تحتاج أدوات متعددة إلى نفس الحالة (على سبيل المثال، كائن المستخدم المستخدم في شريط التنقل + الصفحة الرئيسية + الملف الشخصي).
- تريد فصل الاهتمامات (على سبيل المثال، لا ينبغي أن تعيش منطق الأعمال داخل واجهة المستخدم).
Instead, consider Provider, Riverpod, or BLoC. More on these in Part 2.
بدلاً من ذلك، ضع في اعتبارك Provider أو Riverpod أو BLoC. المزيد عن هذه في الجزء الثاني.
🔥 Try this in your project today: Audit your app for all the setState() calls. If the same variable is being used in more than one screen or widget — it's probably time to move it to a centralized state.
🔥 جرب هذا في مشروعك اليوم: قم بتدقيق تطبيقك لجميع استدعاءات setState (). إذا تم استخدام نفس المتغير في أكثر من شاشة أو أداة - فربما حان الوقت لنقله إلى حالة مركزية.
All blogs are certified by our company and reviewed by our specialists
Issue Number: #5fe8e74d-d333-4ee8-be5d-fc0f7f1594ce