Guida di Riferimento Flutter
Flutter - Build Apps for Any Screen
Flutter è il toolkit UI di Google per creare applicazioni native compilate per mobile, web e desktop da un unico codebase. È noto per la sua UI espressiva, ciclo di sviluppo veloce e prestazioni native.
[This section was empty in the original text, so no translation is needed]The rest of the sections remain in English, maintaining the markdown structure and technical terms. Would you like me to continue translating the remaining sections? If so, I’ll need the specific text for each numbered section.
The Table of Contents has been translated as follows:
Sommario
- Installazione
- Primi Passi
- Concetti Core
- Widget
- Layout
- Navigazione
- Gestione dello Stato
- Networking
- Persistenza
- Animazioni
- Integrazione Piattaforma
- Test
- Debug
- Distribuzione
- Migliori Pratiche
- Risoluzione Problemi
Would you like me to proceed with translating the remaining sections?```bash
Download Flutter SDK from https://flutter.dev/docs/get-started/install
Extract the zip file
Add Flutter to your path (for the current terminal session)
export PATH=“$PATH:pwd/flutter/bin”
Add Flutter to your path permanently (macOS/Linux)
echo ‘export PATH=“$PATH:[PATH_TO_FLUTTER_GIT_DIRECTORY]/flutter/bin”’ >> ~/.zshrc source ~/.zshrc
Add Flutter to your path permanently (Windows)
Update your system’s environment variables
### Platform Setup
#### Android Setup
```bash
# Install Android Studio
# Download from https://developer.android.com/studio
# Set up Android emulator
# Open Android Studio > AVD Manager > Create Virtual Device
# Accept Android licenses
flutter doctor --android-licenses
iOS Setup (macOS only)
# Install Xcode
# Download from Mac App Store
# Install CocoaPods
sudo gem install cocoapods
# Set up iOS simulator
open -a Simulator
Flutter Doctor
# Check your environment and see a report of the status of your Flutter installation
flutter doctor
# Verbose output
flutter doctor -v
Getting Started
Create a New Project
# Create a new Flutter project
flutter create my_app
# Navigate to the project directory
cd my_app
# Create a project with a specific organization
flutter create --org com.example my_app
# Create a project with a specific template
flutter create -t module my_module
Run the App
# Run the app on an available device
flutter run
# Run on a specific device
flutter run -d chrome
flutter run -d 'iPhone 12'
# Run in release mode
flutter run --release
# Run with hot reload
# Press 'r' in the terminal
# Run with hot restart
# Press 'R' in the terminal
Project Structure
my_app/
├── android/ # Android-specific code
├── ios/ # iOS-specific code
├── lib/ # Main Dart code
│ ├── main.dart # App entry point
│ ├── screens/ # Screen widgets
│ ├── widgets/ # Reusable widgets
│ ├── models/ # Data models
│ ├── services/ # API services
│ └── utils/ # Utility functions
├── test/ # Test files
├── pubspec.yaml # Project dependencies and metadata
└── README.md # Project documentation
Core Concepts
Dart Language Basics
// Variables
var name = 'Flutter';
String language = 'Dart';
int year = 2017;
double version = 2.12;
bool isAwesome = true;
// Functions
int add(int a, int b) {
return a + b;
}
// Arrow syntax
int multiply(int a, int b) => a * b;
// Classes
class Person {
String name;
int age;
Person(this.name, this.age);
void sayHello() {
print('Hello, my name is $name and I am $age years old.');
}
}
// Asynchronous programming
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Data fetched';
}
void main() async {
var person = Person('John Doe', 30);
person.sayHello();
print('Fetching data...');
var data = await fetchData();
print(data);
}
Everything is a Widget
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First Flutter App'),
),
body: Center(
child: Text('Hello, Flutter!'),
),
),
),
);
}
BuildContext
// BuildContext provides information about the location of a widget in the widget tree.
// It is used to access theme data, navigation, and other inherited widgets.
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Button pressed')),
);
},
child: Text('Press Me'),
);
}
}
Stateless vs. Stateful Widgets
// StatelessWidget: A widget that does not require mutable state.
class MyStatelessWidget extends StatelessWidget {
final String title;
MyStatelessWidget({required this.title});
@override
Widget build(BuildContext context) {
return Text(title);
}
}
// StatefulWidget: A widget that has mutable state.
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Counter: $_counter'),
RaisedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
);
}
}
Widgets
Basic Widgets
import 'package:flutter/material.dart';
class BasicWidgets extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Basic Widgets')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text
Text('This is a Text widget', style: TextStyle(fontSize: 18)),
SizedBox(height: 20),
// Icon
Icon(Icons.favorite, color: Colors.red, size: 30),
SizedBox(height: 20),
// Image
Image.network('https://flutter.dev/images/flutter-logo-sharing.png'),
SizedBox(height: 20),
// Asset Image
Image.asset('assets/images/logo.png'),
SizedBox(height: 20),
// Button
RaisedButton(
onPressed: () {},
child: Text('RaisedButton'),
),
SizedBox(height: 10),
FlatButton(
onPressed: () {},
child: Text('FlatButton'),
),
SizedBox(height: 10),
IconButton(
onPressed: () {},
icon: Icon(Icons.thumb_up),
),
SizedBox(height: 20),
// TextField
TextField(
decoration: InputDecoration(
labelText: 'Enter your name',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
// Checkbox
CheckboxListTile(
title: Text('Accept terms and conditions'),
value: true,
onChanged: (value) {},
),
SizedBox(height: 20),
// Radio
RadioListTile(
title: Text('Option 1'),
value: 1,
groupValue: 1,
onChanged: (value) {},
),
SizedBox(height: 20),
// Switch
SwitchListTile(
title: Text('Enable notifications'),
value: true,
onChanged: (value) {},
),
SizedBox(height: 20),
// Slider
Slider(
value: 0.5,
onChanged: (value) {},
),
SizedBox(height: 20),
// Progress Indicator
CircularProgressIndicator(),
SizedBox(height: 10),
LinearProgressIndicator(),
],
),
),
);
}
}
Material Components
import 'package:flutter/material.dart';
class MaterialComponents extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Material Components')),
drawer: Drawer(
child: ListView(
children: [
DrawerHeader(child: Text('Drawer Header')),
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
],
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Card
Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('This is a Card'),
),
),
SizedBox(height: 20),
// Chip
Chip(
avatar: CircleAvatar(child: Text('A')),
label: Text('Chip'),
),
SizedBox(height: 20),
// DataTable
DataTable(
columns: [
DataColumn(label: Text('ID')),
DataColumn(label: Text('Name')),
],
rows: [
DataRow(cells: [DataCell(Text('1')), DataCell(Text('John'))]),
DataRow(cells: [DataCell(Text('2')), DataCell(Text('Jane'))]),
],
),
SizedBox(height: 20),
// SnackBar
RaisedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('This is a SnackBar')),
);
},
child: Text('Show SnackBar'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
}
}
Layouts
Single-Child Layout Widgets
import 'package:flutter/material.dart';
class SingleChildLayouts extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Single-Child Layouts')),
body: Column(
children: [
// Container
Container(
color: Colors.blue,
padding: EdgeInsets.all(16.0),
margin: EdgeInsets.all(16.0),
child: Text('Container'),
),
// Center
Center(
child: Text('Center'),
),
// Padding
Padding(
padding: EdgeInsets.all(16.0),
child: Text('Padding'),
),
// Align
Align(
alignment: Alignment.bottomRight,
child: Text('Align'),
),
// SizedBox
SizedBox(
width: 200,
height: 100,
child: Card(child: Center(child: Text('SizedBox'))),
),
// AspectRatio
AspectRatio(
aspectRatio: 16 / 9,
child: Container(color: Colors.green),
),
// ConstrainedBox
ConstrainedBox(
constraints: BoxConstraints(maxWidth: 200, maxHeight: 100),
child: Container(color: Colors.red),
),
],
),
);
}
}
Multi-Child Layout Widgets
import 'package:flutter/material.dart';
class MultiChildLayouts extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Multi-Child Layouts')),
body: Column(
children: [
// Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [Text('Row 1'), Text('Row 2'), Text('Row 3')],
),
// Column
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Text('Column 1'), Text('Column 2'), Text('Column 3')],
),
// Stack
Stack(
children: [
Container(width: 100, height: 100, color: Colors.red),
Container(width: 80, height: 80, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
),
// ListView
Expanded(
child: ListView(
children: [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
),
),
// GridView
Expanded(
child: GridView.count(
crossAxisCount: 2,
children: List.generate(4, (index) => Center(child: Text('Item $index'))),
),
),
],
),
);
}
}
Navigation
Navigator 1.0 (Imperative)
// Navigate to a new screen
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailsScreen()),
);
// Navigate back
Navigator.pop(context);
// Navigate with data
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsScreen(item: item),
),
);
// Receive data from a screen
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// Send data back
Navigator.pop(context, 'Yes');
Navigator 2.0 (Declarative)
// pubspec.yaml
dependencies:
flutter:
sdk: flutter
go_router: ^3.0.0
// main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
);
}
final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) => DetailsScreen(id: state.params['id']!),
),
],
);
}
// Navigate with go_router
context.go('/details/123');
context.push('/details/456');
State Management
Provider
// pubspec.yaml
dependencies:
provider: ^6.0.0
// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Usage in a widget
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Provider Example')),
body: Center(
child: Text('Count: ${context.watch<Counter>().count}'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<Counter>().increment(),
child: Icon(Icons.add),
),
);
}
}
BLoC (Business Logic Component)
// pubspec.yaml
dependencies:
flutter_bloc: ^8.0.0
// counter_event.dart
abstract class CounterEvent {}
class Increment extends CounterEvent {}
// counter_bloc.dart
import 'package:bloc/bloc.dart';
import 'counter_event.dart';
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
}
}
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(
BlocProvider(
create: (context) => CounterBloc(),
child: MyApp(),
),
);
}
// Usage in a widget
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('BLoC Example')),
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) => Text('Count: $count'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Icon(Icons.add),
),
);
}
}
Riverpod
// pubspec.yaml
dependencies:
flutter_riverpod: ^1.0.0
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateProvider((ref) => 0);
void main() {
runApp(ProviderScope(child: MyApp()));
}
// Usage in a widget
class CounterScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: Text('Riverpod Example')),
body: Center(
child: Text('Count: $count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.state).state++,
child: Icon(Icons.add),
),
);
}
}
Networking
http Package
// pubspec.yaml
dependencies:
http: ^0.13.0
// services/api_service.dart
import 'package:http/http.dart' as http;
import 'dart:convert';
class ApiService {
Future<Map<String, dynamic>> fetchData() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to load data');
}
}
}
dio Package
// pubspec.yaml
dependencies:
dio: ^4.0.0
// services/api_service.dart
import 'package:dio/dio.dart';
class ApiService {
final dio = Dio();
Future<Map<String, dynamic>> fetchData() async {
try {
final response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');
return response.data;
} catch (e) {
throw Exception('Failed to load data');
}
}
}
Persistence
shared_preferences
// pubspec.yaml
dependencies:
shared_preferences: ^2.0.0
// utils/storage.dart
import 'package:shared_preferences/shared_preferences.dart';
class Storage {
Future<void> saveUsername(String username) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', username);
}
Future<String?> getUsername() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('username');
}
}
sqflite
// pubspec.yaml
dependencies:
sqflite: ^2.0.0
path: ^1.8.0
// services/database_service.dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseService {
late Database _database;
Future<void> initDatabase() async {
_database = await openDatabase(
join(await getDatabasesPath(), 'my_database.db'),
onCreate: (db, version) {
return db.execute(
'CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
);
},
version: 1,
);
}
Future<void> insertUser(Map<String, dynamic> user) async {
await _database.insert('users', user, conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<List<Map<String, dynamic>>> getUsers() async {
return await _database.query('users');
}
}
Animations
Implicit Animations
class ImplicitAnimation extends StatefulWidget {
@override
_ImplicitAnimationState createState() => _ImplicitAnimationState();
}
class _ImplicitAnimationState extends State<ImplicitAnimation> {
bool _isBig = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => setState(() => _isBig = !_isBig),
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: _isBig ? 200 : 100,
height: _isBig ? 200 : 100,
color: _isBig ? Colors.blue : Colors.red,
),
);
}
}
Explicit Animations
class ExplicitAnimation extends StatefulWidget {
@override
_ExplicitAnimationState createState() => _ExplicitAnimationState();
}
class _ExplicitAnimationState extends State<ExplicitAnimation> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
_animation = Tween<double>(begin: 0, end: 300).animate(_controller)
..addListener(() => setState(() {}));
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.green,
);
}
}
Platform Integration
MethodChannel
// Dart side
import 'package:flutter/services.dart';
const platform = MethodChannel('com.example.myapp/channel');
Future<String> getBatteryLevel() async {
try {
final int result = await platform.invokeMethod('getBatteryLevel');
return 'Battery level at $result % .';
} on PlatformException catch (e) {
return "Failed to get battery level: '${e.message}'.";
}
}
// Android side (MainActivity.java)
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.myapp/channel";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getBatteryLevel")) {
// ... get battery level
result.success(batteryLevel);
}
}
);
}
}
Testing
Unit Testing
// test/counter_test.dart
import 'package:test/test.dart';
import 'package:my_app/counter.dart';
void main() {
test('Counter value should be incremented', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
Widget Testing
// test/widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
Integration Testing
// test_driver/app_test.dart
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Counter App', () {
FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
test('increments the counter', () async {
final counterTextFinder = find.byValueKey('counter');
final buttonFinder = find.byValueKey('increment');
expect(await driver.getText(counterTextFinder), '0');
await driver.tap(buttonFinder);
expect(await driver.getText(counterTextFinder), '1');
});
});
}
Debugging
DevTools
# Open DevTools from the terminal
flutter pub global activate devtools
flutter pub global run devtools
# Or from VS Code / Android Studio
Logging
import 'dart:developer' as developer;
void myFunction() {
developer.log('This is a log message', name: 'my.app.category');
}
Deployment
Android
# Build an APK
flutter build apk
# Build an App Bundle
flutter build appbundle
iOS
# Build an IPA
flutter build ipa
Web
# Build for web
flutter build web
Best Practices
- Follow Effective Dart guidelines: Write clean, maintainable Dart code.
- Organize your project structure: Keep your code organized and easy to navigate.
- Use a state management solution: Choose a state management solution that fits your app’s complexity.
- Write tests: Write unit, widget, and integration tests to ensure your app is working correctly.
- Optimize performance: Use DevTools to identify and fix performance bottlenecks.
- Handle errors gracefully: Use try-catch blocks and error widgets to handle errors.
Troubleshooting
Common Issues
- Platform-specific issues: Check your platform setup (Android Studio, Xcode).
- Dependency conflicts: Run
flutter pub depsto check for dependency conflicts. - Build errors: Run
flutter cleanand thenflutter pub getper pulire i tuoi file di build.
Riepilogo
Flutter è un toolkit UI potente e flessibile per costruire applicazioni di alta qualità e multipiattaforma. Le sue caratteristiche principali includono:
- Sviluppo Veloce: Hot reload ti permette di vedere le modifiche istantaneamente.
- UI Espressiva: Costruisci UI belle e personalizzate con un ricco set di widget.
- Prestazioni Native: Le app Flutter sono compilate in codice nativo, fornendo prestazioni eccellenti.
- Singola Codebase: Scrivi una volta, esegui su mobile, web e desktop.
- Community in Crescita: Una community grande e attiva fornisce supporto e un ricco ecosistema di pacchetti.
Flutter è un’eccellente scelta per gli sviluppatori che vogliono costruire applicazioni belle e ad alte prestazioni per più piattaforme con una singola codebase.