Answer
Overview
Widgets are the building blocks of Flutter apps. Everything you see on the screen (buttons, text, layouts, animations) is a widget. In Flutter, everything is a widget.
What is a Widget?
A widget is a description of part of the user interface. Widgets are immutable - once created, they cannot be changed.
dartText('Hello World') // Text widget ElevatedButton( // Button widget onPressed: () {}, child: Text('Click'), ) Container( // Layout widget color: Colors.blue, child: Text('Box'), )
Widget Tree
Widgets are organized in a tree structure:
textMaterialApp └─ Scaffold ├─ AppBar │ └─ Text('Title') └─ Column ├─ Text('Hello') ├─ ElevatedButton │ └─ Text('Click') └─ Image
Types of Widgets
1. StatelessWidget (Immutable)
Widgets that don't change once built.
dartclass Greeting extends StatelessWidget { final String name; const Greeting({required this.name}); Widget build(BuildContext context) { return Text('Hello, $name!'); } }
Examples:
- Text
- Icon
- Image
- Container (without changing properties)
Use When:
- Display static content
- UI doesn't change based on user interaction
- Purely presentational
2. StatefulWidget (Mutable)
Widgets that can change over time.
dartclass Counter extends StatefulWidget { _CounterState createState() => _CounterState(); } class _CounterState extends State<Counter> { int _count = 0; Widget build(BuildContext context) { return Column( children: [ Text('Count: $_count'), ElevatedButton( onPressed: () => setState(() => _count++), child: Text('Increment'), ), ], ); } }
Examples:
- Checkbox
- TextField
- Slider
- Animated widgets
Use When:
- User interaction changes UI
- Data changes over time
- Animations
Widget Categories
1. Layout Widgets
Arrange other widgets.
dart// Row - Horizontal layout Row( children: [ Icon(Icons.star), Text('5.0'), ], ) // Column - Vertical layout Column( children: [ Text('Title'), Text('Subtitle'), ], ) // Stack - Overlapping widgets Stack( children: [ Image.asset('background.jpg'), Positioned( top: 20, left: 20, child: Text('Overlay'), ), ], ) // Container - Box model Container( width: 200, height: 100, color: Colors.blue, padding: EdgeInsets.all(16), child: Text('Box'), )
Common Layout Widgets:
- Row, Column
- Stack
- Container
- Padding
- Center
- Align
- Expanded
- Flexible
2. Material Design Widgets
Pre-built Material Design components.
dart// Scaffold - App structure Scaffold( appBar: AppBar(title: Text('App')), body: Center(child: Text('Content')), floatingActionButton: FloatingActionButton( onPressed: () {}, child: Icon(Icons.add), ), ) // ElevatedButton ElevatedButton( onPressed: () {}, child: Text('Click Me'), ) // Card Card( child: Padding( padding: EdgeInsets.all(16), child: Text('Card Content'), ), ) // ListTile ListTile( leading: Icon(Icons.person), title: Text('John Doe'), subtitle: Text('john@example.com'), trailing: Icon(Icons.arrow_forward), )
3. Input Widgets
Handle user input.
dart// TextField TextField( decoration: InputDecoration( labelText: 'Enter name', hintText: 'John Doe', ), onChanged: (value) => print(value), ) // Checkbox Checkbox( value: true, onChanged: (value) {}, ) // Switch Switch( value: false, onChanged: (value) {}, ) // Slider Slider( value: 50, min: 0, max: 100, onChanged: (value) {}, )
4. Display Widgets
Show content to users.
dart// Text Text( 'Hello World', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ) // Image from network Image.network('https://example.com/image.jpg') // Image from assets Image.asset('assets/logo.png') // Icon Icon(Icons.favorite, color: Colors.red, size: 32)
5. Cupertino Widgets (iOS Style)
iOS-style widgets.
dartimport 'package:flutter/cupertino.dart'; // iOS-style button CupertinoButton( child: Text('iOS Button'), onPressed: () {}, ) // iOS-style switch CupertinoSwitch( value: true, onChanged: (value) {}, ) // iOS-style navigation bar CupertinoNavigationBar( middle: Text('iOS App'), )
Widget Composition
Build complex UIs by composing simple widgets.
dartclass ProfileCard extends StatelessWidget { final String name; final String email; final String imageUrl; const ProfileCard({ required this.name, required this.email, required this.imageUrl, }); Widget build(BuildContext context) { return Card( child: Padding( padding: EdgeInsets.all(16), child: Row( children: [ CircleAvatar( backgroundImage: NetworkImage(imageUrl), radius: 30, ), SizedBox(width: 16), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( name, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), SizedBox(height: 4), Text( email, style: TextStyle(color: Colors.grey), ), ], ), ], ), ), ); } } // Usage ProfileCard( name: 'John Doe', email: 'john@example.com', imageUrl: 'https://example.com/avatar.jpg )
Widget Lifecycle
StatelessWidget Lifecycle
textbuild()
Simple: just build once.
StatefulWidget Lifecycle
textcreateState() → initState() → build() ↓ setState() → build() ↓ dispose()
Key Widget Properties
Common Properties
Most widgets accept these properties:
dartWidget( key: Key('unique_key'), // Unique identifier child: Widget(), // Single child children: [Widget(), Widget()],// Multiple children )
Container Properties
dartContainer( width: 200, height: 100, color: Colors.blue, padding: EdgeInsets.all(16), margin: EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10), boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 10)], ), child: Text('Content'), )
Complete Example: Login Screen
dartclass LoginScreen extends StatefulWidget { _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; Future<void> _login() async { setState(() => _isLoading = true); // Simulate API call await Future.delayed(Duration(seconds: 2)); setState(() => _isLoading = false); } void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Login')), body: Padding( padding: EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Logo FlutterLogo(size: 100), SizedBox(height: 32), // Email field TextField( controller: _emailController, decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), ), keyboardType: TextInputType.emailAddress, ), SizedBox(height: 16), // Password field TextField( controller: _passwordController, decoration: InputDecoration( labelText: 'Password', border: OutlineInputBorder(), prefixIcon: Icon(Icons.lock), ), obscureText: true, ), SizedBox(height: 24), // Login button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _isLoading ? null : _login, child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('Login'), ), ), // Forgot password TextButton( onPressed: () {}, child: Text('Forgot Password?'), ), ], ), ), ); } }
Best Practices
Important: Extract reusable widgets into separate classes
✅ Do
dart// Good - Extract widget class CustomButton extends StatelessWidget { final String text; final VoidCallback onPressed; const CustomButton({required this.text, required this.onPressed}); Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed, child: Text(text), ); } } // Good - Use const constructors const Text('Hello') const Icon(Icons.star)
❌ Don't
dart// Bad - Methods returning widgets Widget _buildButton() { return ElevatedButton(...); } // Bad - Creating widgets in build Widget build(BuildContext context) { return Column( children: [ for (var i = 0; i < 100; i++) Container(), // ❌ Creates 100 widgets every build ], ); }