Flutter 示例
Flutter Dart 移动开发框架示例,包括小部件、状态管理、导航和平台集成
💻 Flutter 你好世界 dart
🟢 simple
基础 Flutter 应用示例,包含小部件、布局、样式和基本概念
// Flutter Hello World Examples
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// 1. Basic Hello World App
class HelloWorldApp extends StatelessWidget {
const HelloWorldApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const HelloWorldScreen(),
);
}
}
class HelloWorldScreen extends StatelessWidget {
const HelloWorldScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Hello World'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Hello, World!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 16),
Text(
'Welcome to Flutter!',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
),
),
);
}
}
// 2. Interactive Counter App
class CounterApp extends StatefulWidget {
const CounterApp({super.key});
@override
State<CounterApp> createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _decrementCounter() {
setState(() {
_counter--;
});
}
void _resetCounter() {
setState(() {
_counter = 0;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Counter App',
theme: ThemeData(
primarySwatch: Colors.green,
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Counter App'),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'You have pushed the button this many times:',
style: TextStyle(fontSize: 16),
),
Text(
'$_counter',
style: const TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
const SizedBox(height: 32),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FloatingActionButton(
onPressed: _decrementCounter,
tooltip: 'Decrement',
backgroundColor: Colors.red,
child: const Icon(Icons.remove),
),
FloatingActionButton(
onPressed: _resetCounter,
tooltip: 'Reset',
backgroundColor: Colors.orange,
child: const Icon(Icons.refresh),
),
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
backgroundColor: Colors.green,
child: const Icon(Icons.add),
),
],
),
],
),
),
),
);
}
}
// 3. User Profile Form
class UserProfileForm extends StatefulWidget {
const UserProfileForm({super.key});
@override
State<UserProfileForm> createState() => _UserProfileFormState();
}
class _UserProfileFormState extends State<UserProfileForm> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _ageController = TextEditingController();
final _bioController = TextEditingController();
bool _isEditing = false;
Map<String, String> _userProfile = {};
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_ageController.dispose();
_bioController.dispose();
super.dispose();
}
void _toggleEditMode() {
setState(() {
_isEditing = !_isEditing;
if (_isEditing) {
_nameController.text = _userProfile['name'] ?? '';
_emailController.text = _userProfile['email'] ?? '';
_ageController.text = _userProfile['age'] ?? '';
_bioController.text = _userProfile['bio'] ?? '';
}
});
}
void _saveProfile() {
if (_formKey.currentState!.validate()) {
setState(() {
_userProfile = {
'name': _nameController.text,
'email': _emailController.text,
'age': _ageController.text,
'bio': _bioController.text,
};
_isEditing = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Profile saved successfully!'),
backgroundColor: Colors.green,
),
);
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'User Profile',
theme: ThemeData(
primarySwatch: Colors.purple,
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: Text(_isEditing ? 'Edit Profile' : 'User Profile'),
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
actions: [
IconButton(
icon: Icon(_isEditing ? Icons.save : Icons.edit),
onPressed: _isEditing ? _saveProfile : _toggleEditMode,
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!_isEditing && _userProfile.isNotEmpty) ...[
_buildProfileDisplay(),
] else ...[
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Name',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your name';
}
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _emailController,
decoration: const InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
if (!value.contains('@')) {
return 'Please enter a valid email';
}
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _ageController,
decoration: const InputDecoration(
labelText: 'Age',
prefixIcon: Icon(Icons.cake),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your age';
}
if (int.tryParse(value) == null) {
return 'Please enter a valid number';
}
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _bioController,
decoration: const InputDecoration(
labelText: 'Bio',
prefixIcon: Icon(Icons.description),
border: OutlineInputBorder(),
),
maxLines: 3,
),
const SizedBox(height: 24),
if (_isEditing)
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _saveProfile,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('Save Profile'),
),
),
const SizedBox(width: 16),
Expanded(
child: OutlinedButton(
onPressed: _toggleEditMode,
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('Cancel'),
),
),
],
),
],
],
),
),
),
),
);
}
Widget _buildProfileDisplay() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoCard('Name', _userProfile['name']!, Icons.person),
_buildInfoCard('Email', _userProfile['email']!, Icons.email),
_buildInfoCard('Age', _userProfile['age']!, Icons.cake),
if (_userProfile['bio']!.isNotEmpty)
_buildInfoCard('Bio', _userProfile['bio']!, Icons.description),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _toggleEditMode,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
minimumSize: const Size(double.infinity, 48),
),
child: const Text('Edit Profile'),
),
],
);
}
Widget _buildInfoCard(String label, String value, IconData icon) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: ListTile(
leading: Icon(icon, color: Colors.purple),
title: Text(label),
subtitle: Text(value),
),
);
}
}
// 4. Todo List App
class TodoApp extends StatefulWidget {
const TodoApp({super.key});
@override
State<TodoApp> createState() => _TodoAppState();
}
class _TodoAppState extends State<TodoApp> {
final List<Todo> _todos = [];
final TextEditingController _textFieldController = TextEditingController();
void _addTodoItem(String title) {
if (title.isNotEmpty) {
setState(() {
_todos.add(Todo(
title: title,
createdAt: DateTime.now(),
));
});
_textFieldController.clear();
}
}
void _toggleTodoStatus(int index) {
setState(() {
_todos[index].isDone = !_todos[index].isDone;
});
}
void _deleteTodoItem(int index) {
setState(() {
_todos.removeAt(index);
});
}
void _clearCompleted() {
setState(() {
_todos.removeWhere((todo) => todo.isDone);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
theme: ThemeData(
primarySwatch: Colors.teal,
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Todo List'),
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textFieldController,
decoration: InputDecoration(
labelText: 'What needs to be done?',
hintText: 'Enter a todo item',
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: const Icon(Icons.add),
onPressed: () => _addTodoItem(_textFieldController.text),
),
),
onSubmitted: _addTodoItem,
),
),
],
),
),
_buildStatsBar(),
Expanded(
child: ListView.builder(
itemCount: _todos.length,
itemBuilder: (context, index) {
final todo = _todos[index];
return Dismissible(
key: Key(todo.title),
background: Container(
color: Colors.red,
alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 20.0),
child: const Icon(Icons.delete, color: Colors.white),
),
onDismissed: (direction) {
_deleteTodoItem(index);
},
child: ListTile(
leading: Checkbox(
value: todo.isDone,
onChanged: (value) => _toggleTodoStatus(index),
activeColor: Colors.teal,
),
title: Text(
todo.title,
style: TextStyle(
decoration: todo.isDone ? TextDecoration.lineThrough : null,
color: todo.isDone ? Colors.grey : null,
),
),
subtitle: Text(
'Created: ${_formatDate(todo.createdAt)}',
style: const TextStyle(fontSize: 12),
),
trailing: IconButton(
icon: const Icon(Icons.delete_outline),
onPressed: () => _deleteTodoItem(index),
),
),
);
},
),
),
],
),
),
);
}
Widget _buildStatsBar() {
final completedCount = _todos.where((todo) => todo.isDone).length;
final totalCount = _todos.length;
final activeCount = totalCount - completedCount;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
color: Colors.teal.withOpacity(0.1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('$activeCount active, $completedCount completed'),
if (completedCount > 0)
TextButton(
onPressed: _clearCompleted,
child: const Text('Clear completed'),
),
],
),
);
}
String _formatDate(DateTime date) {
return '${date.day}/${date.month}/${date.year}';
}
}
class Todo {
String title;
DateTime createdAt;
bool isDone;
Todo({
required this.title,
required this.createdAt,
this.isDone = false,
});
}
// 5. Main Demo App
class FlutterDemoApp extends StatefulWidget {
const FlutterDemoApp({super.key});
@override
State<FlutterDemoApp> createState() => _FlutterDemoAppState();
}
class _FlutterDemoAppState extends State<FlutterDemoApp> {
int _selectedIndex = 0;
final List<Widget> _pages = [
const HomePage(),
const CounterPage(),
const ProfilePage(),
const TodoPage(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.indigo,
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo App'),
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
),
body: _pages[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
selectedItemColor: Colors.indigo,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.countertops),
label: 'Counter',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
BottomNavigationBarItem(
icon: Icon(Icons.checklist),
label: 'Todos',
),
],
),
),
);
}
}
// Page widgets
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Welcome to Flutter!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
SizedBox(height: 16),
Text(
'This is a comprehensive Flutter demo showcasing:',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 8),
_FeatureList(),
],
),
);
}
}
class _FeatureList extends StatelessWidget {
const _FeatureList({super.key});
@override
Widget build(BuildContext context) {
final features = [
'📱 Cross-platform mobile development',
'🎨 Beautiful Material Design UI',
'⚡ Fast development with Hot Reload',
'🔄 Reactive state management',
'🧩 Reusable widgets',
'🧪 Built-in testing support',
'📦 Rich package ecosystem',
'🎯 Native performance',
];
return Column(
children: features.map((feature) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Expanded(
child: Text(
feature,
style: const TextStyle(fontSize: 14),
),
),
],
),
)).toList(),
);
}
}
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'Counter Page
Navigate to see the counter app',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
);
}
}
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'Profile Page
Navigate to see the profile form',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
);
}
}
class TodoPage extends StatelessWidget {
const TodoPage({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'Todo Page
Navigate to see the todo list app',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
);
}
}
// Main entry point for running individual apps
void main() {
runApp(const FlutterDemoApp());
} // Change to HelloWorldApp(), CounterApp(), etc. to run individual apps
💻 Flutter Widgets and Layouts dart
🟡 intermediate
Comprehensive guide to Flutter widgets, layouts, and responsive design patterns
// Flutter Widgets and Layouts Examples
import 'package:flutter/material.dart';
// 1. Basic Layout Widgets
class LayoutWidgetsDemo extends StatelessWidget {
const LayoutWidgetsDemo({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Layout Widgets Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
useMaterial3: true,
),
home: const LayoutWidgetsScreen(),
);
}
}
class LayoutWidgetsScreen extends StatelessWidget {
const LayoutWidgetsScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Layout Widgets'),
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Layout Widgets',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.purple,
),
),
const SizedBox(height: 16),
_ContainerExample(),
const SizedBox(height: 24),
_RowExample(),
const SizedBox(height: 24),
_ColumnExample(),
const SizedBox(height: 24),
_StackExample(),
const SizedBox(height: 24),
_ListViewExample(),
const SizedBox(height: 24),
_GridViewExample(),
const SizedBox(height: 24),
_WrapExample(),
const SizedBox(height: 24),
_ExpandedExample(),
],
),
),
);
}
Widget _ContainerExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Container',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Row(
children: [
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(right: 8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(8),
),
child: const Text('Styled Container'),
),
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.purple, Colors.pink],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.purple.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: const Center(
child: Text(
'Gradient',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
);
}
Widget _RowExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Row',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
flex: 2,
child: Text('Flexible Item 1'),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'Fixed',
style: TextStyle(color: Colors.white),
),
),
const SizedBox(width: 16),
const Expanded(
flex: 1,
child: Text('Item 2'),
),
],
),
),
],
);
}
Widget _ColumnExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Column',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: 40,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Text(
'Header Item',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 8),
const Expanded(
child: Text('Flexible content that can expand or contract'),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(color: Colors.orange),
borderRadius: BorderRadius.circular(4),
),
child: const Text('Footer Item'),
),
],
),
),
],
);
}
Widget _StackExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Stack',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
SizedBox(
height: 200,
child: Container(
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Stack(
children: [
// Background layer
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red.withOpacity(0.2), Colors.pink.withOpacity(0.2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(8),
),
),
),
// Middle layer
Positioned(
top: 50,
left: 50,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50),
boxShadow: [
BoxShadow(
color: Colors.red.withOpacity(0.3),
spreadRadius: 4,
blurRadius: 8,
),
],
),
child: const Center(
child: Icon(
Icons.favorite,
size: 40,
color: Colors.red,
),
),
),
),
// Top layer
Positioned(
bottom: 20,
right: 20,
child: FloatingActionButton.small(
onPressed: () {},
backgroundColor: Colors.pink,
child: const Icon(Icons.add),
),
),
],
),
),
),
],
);
}
Widget _ListViewExample() {
final items = List.generate(20, (index) => 'Item ${index + 1}');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'ListView',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
SizedBox(
height: 200,
child: Container(
decoration: BoxDecoration(
color: Colors.teal.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: items.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.teal,
child: Text(
'${index + 1}',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
title: Text(items[index]),
subtitle: Text('Subtitle for ${items[index]}'),
trailing: const Icon(Icons.arrow_forward_ios),
),
);
},
),
),
),
],
);
}
Widget _GridViewExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'GridView',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
SizedBox(
height: 200,
child: Container(
decoration: BoxDecoration(
color: Colors.amber.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: GridView.builder(
padding: const EdgeInsets.all(8),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1,
),
itemCount: 6,
itemBuilder: (context, index) {
final colors = [Colors.amber, Colors.orange, Colors.deepOrange];
final icons = [Icons.star, Icons.favorite, Icons.thumb_up];
return Container(
decoration: BoxDecoration(
color: colors[index % colors.length],
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icons[index % icons.length],
size: 40,
color: Colors.white,
),
const SizedBox(height: 8),
Text(
'Grid ${index + 1}',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
);
},
),
),
),
],
);
}
Widget _WrapExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Wrap',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
'Flutter',
'Dart',
'Mobile',
'Cross-platform',
'Widgets',
'State Management',
'Navigation',
'Animation',
'Testing',
'Performance',
].map((tag) {
final colors = [
Colors.blue,
Colors.purple,
Colors.pink,
Colors.indigo,
Colors.cyan,
];
final color = colors[tag.length % colors.length];
return Chip(
label: Text(tag),
backgroundColor: color.withOpacity(0.1),
labelStyle: TextStyle(
color: color,
fontWeight: FontWeight.w500,
),
side: BorderSide(color: color.withOpacity(0.3)),
);
}).toList(),
),
),
],
);
}
Widget _ExpandedExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Expanded & Flexible',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
height: 150,
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Text(
'Expanded (flex: 1)',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
Flexible(
flex: 2,
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Text(
'Flexible (flex: 2)',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
Expanded(
flex: 1,
child: Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Text(
'Expanded (flex: 1)',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
),
),
],
);
}
}
// 2. Responsive Design with LayoutBuilder
class ResponsiveDesignDemo extends StatelessWidget {
const ResponsiveDesignDemo({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Responsive Design Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const ResponsiveDesignScreen(),
);
}
}
class ResponsiveDesignScreen extends StatelessWidget {
const ResponsiveDesignScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Responsive Design'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Responsive Layouts',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
const SizedBox(height: 16),
_LayoutBuilderExample(),
const SizedBox(height: 24),
_MediaQueryExample(),
const SizedBox(height: 24),
_OrientationExample(),
const SizedBox(height: 24),
_AspectRatioExample(),
],
),
),
);
}
Widget _LayoutBuilderExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'LayoutBuilder',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return _WideLayout();
} else {
return _NarrowLayout();
}
},
),
],
);
}
Widget _WideLayout() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue),
),
child: Row(
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(Icons.desktop_mac, size: 48, color: Colors.blue),
const SizedBox(height: 8),
const Text(
'Wide Layout',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
const SizedBox(height: 8),
const Text(
'This layout is shown on screens wider than 600px',
style: TextStyle(fontSize: 14),
),
],
),
),
const SizedBox(width: 32),
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
),
],
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Content Area',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'This is the content area for wide screens. '
'We can use the extra space for more detailed content or side-by-side layouts.',
style: TextStyle(fontSize: 14),
),
],
),
),
),
],
),
);
}
Widget _NarrowLayout() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue),
),
child: Column(
children: [
const Icon(Icons.smartphone, size: 48, color: Colors.blue),
const SizedBox(height: 8),
const Text(
'Narrow Layout',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
const SizedBox(height: 8),
const Text(
'This layout is shown on screens narrower than 600px',
style: TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 4,
),
],
),
child: const Text(
'Content is stacked vertically on narrow screens to optimize for mobile viewing.',
style: TextStyle(fontSize: 14),
),
),
],
),
);
}
Widget _MediaQueryExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'MediaQuery',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Builder(
builder: (context) {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final isTablet = screenWidth > 600 && screenWidth < 1200;
final isDesktop = screenWidth >= 1200;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.purple.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.purple),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
isDesktop
? Icons.desktop_windows
: isTablet
? Icons.tablet_mac
: Icons.phone_android,
size: 48,
color: Colors.purple,
),
const SizedBox(height: 8),
Text(
'Screen Size: ${screenWidth.toStringAsFixed(0)} x ${screenHeight.toStringAsFixed(0)}',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Device Type: ${isDesktop ? 'Desktop' : isTablet ? 'Tablet' : 'Mobile'}',
style: const TextStyle(fontSize: 14),
),
],
),
);
},
),
],
);
}
Widget _OrientationExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Orientation',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
OrientationBuilder(
builder: (context, orientation) {
final isPortrait = orientation == Orientation.portrait;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.orange),
),
child: Column(
children: [
Icon(
isPortrait ? Icons.phone_iphone : Icons.screen_rotation,
size: 48,
color: Colors.orange,
),
const SizedBox(height: 8),
Text(
'Orientation: ${isPortrait ? 'Portrait' : 'Landscape'}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
isPortrait
? 'Content is optimized for portrait viewing'
: 'Content is optimized for landscape viewing',
style: const TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
if (!isPortrait)
Container(
margin: const EdgeInsets.only(top: 16),
child: const Row(
children: [
Expanded(
child: Placeholder(),
),
SizedBox(width: 16),
Expanded(
child: Placeholder(),
),
],
),
),
],
),
);
},
),
],
);
}
Widget _AspectRatioExample() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'AspectRatio',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.teal.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.teal),
),
child: Column(
children: [
const Text(
'16:9 Aspect Ratio',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
AspectRatio(
aspectRatio: 16 / 9,
child: Container(
decoration: BoxDecoration(
color: Colors.teal,
borderRadius: BorderRadius.circular(8),
),
child: const Center(
child: Text(
'Video Content',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
),
const SizedBox(height: 16),
const Text(
'1:1 Aspect Ratio',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
AspectRatio(
aspectRatio: 1 / 1,
child: Container(
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.circular(8),
),
child: const Center(
child: Icon(
Icons.photo,
size: 48,
color: Colors.white,
),
),
),
),
],
),
),
],
);
}
}
// 3. Custom Widget Example
class CustomWidgetDemo extends StatefulWidget {
const CustomWidgetDemo({super.key});
@override
State<CustomWidgetDemo> createState() => _CustomWidgetDemoState();
}
class _CustomWidgetDemoState extends State<CustomWidgetDemo> {
int _rating = 3;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom Widget Demo',
theme: ThemeData(
primarySwatch: Colors.red,
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Custom Widgets'),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Custom Widgets',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
const SizedBox(height: 16),
const CustomCard(
title: 'Custom Card Widget',
description: 'This is a reusable custom card component',
icon: Icons.star,
color: Colors.red,
),
const SizedBox(height: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Interactive Rating Widget',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
RatingWidget(
rating: _rating,
onRatingChanged: (rating) {
setState(() {
_rating = rating;
});
},
),
const SizedBox(height: 8),
Text(
'Current Rating: $_rating',
style: const TextStyle(fontSize: 16),
),
],
),
const SizedBox(height: 16),
const ProgressIndicatorWidget(
progress: 0.75,
label: 'Project Completion',
),
const SizedBox(height: 16),
_buildAnimatedContainer(),
],
),
),
),
);
}
Widget _buildAnimatedContainer() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Animated Container',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const AnimatedContainerWidget(),
],
);
}
}
// Custom Card Widget
class CustomCard extends StatelessWidget {
final String title;
final String description;
final IconData icon;
final Color color;
const CustomCard({
super.key,
required this.title,
required this.description,
required this.icon,
required this.color,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
color.withOpacity(0.1),
color.withOpacity(0.05),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: color.withOpacity(0.3)),
boxShadow: [
BoxShadow(
color: color.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: Colors.white, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: color,
),
),
const SizedBox(height: 4),
Text(
description,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
],
),
);
}
}
// Rating Widget
class RatingWidget extends StatefulWidget {
final int rating;
final ValueChanged<int>? onRatingChanged;
const RatingWidget({
super.key,
required this.rating,
this.onRatingChanged,
});
@override
State<RatingWidget> createState() => _RatingWidgetState();
}
class _RatingWidgetState extends State<RatingWidget> {
late int _rating;
@override
void initState() {
super.initState();
_rating = widget.rating;
}
void _updateRating(int newRating) {
setState(() {
_rating = newRating;
});
widget.onRatingChanged?.call(newRating);
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(5, (index) {
return IconButton(
onPressed: () => _updateRating(index + 1),
icon: Icon(
index < _rating ? Icons.star : Icons.star_border,
color: index < _rating ? Colors.amber : Colors.grey,
size: 32,
),
);
}),
);
}
}
// Progress Indicator Widget
class ProgressIndicatorWidget extends StatelessWidget {
final double progress;
final String label;
const ProgressIndicatorWidget({
super.key,
required this.progress,
required this.label,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
'${(progress * 100).toInt()}%',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
Container(
height: 8,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
widthFactor: progress,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.green, Colors.lightGreen],
),
borderRadius: BorderRadius.circular(4),
),
),
),
),
],
),
);
}
}
// Animated Container Widget
class AnimatedContainerWidget extends StatefulWidget {
const AnimatedContainerWidget({super.key});
@override
State<AnimatedContainerWidget> createState() => _AnimatedContainerWidgetState();
}
class _AnimatedContainerWidgetState extends State<AnimatedContainerWidget> {
Color _color = Colors.blue;
double _width = 100;
double _height = 100;
BorderRadius _borderRadius = BorderRadius.circular(8);
void _animateProperties() {
setState(() {
_color = Colors.primaries[(DateTime.now().millisecond % Colors.primaries.length)];
_width = 80 + (DateTime.now().millisecond % 120);
_height = 80 + (DateTime.now().millisecond % 120);
_borderRadius = BorderRadius.circular(8 + (DateTime.now().millisecond % 32));
});
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Animated Container',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _width,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: _borderRadius,
boxShadow: [
BoxShadow(
color: _color.withOpacity(0.3),
spreadRadius: 4,
blurRadius: 12,
offset: const Offset(0, 6),
),
],
),
child: const Center(
child: Text(
'Tap to Animate',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _animateProperties,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
child: const Text('Animate Properties'),
),
],
);
}
}
// Main entry point
void main() {
runApp(const LayoutWidgetsDemo());
}