Hoja de Referencia de Flutter¶
Flutter - Build Apps for Any Screen
Flutter es el kit de herramientas de UI de Google para crear aplicaciones compiladas nativamente hermosas para móvil, web y escritorio desde una única base de código. Es conocido por su UI expresiva, ciclo de desarrollo rápido y rendimiento nativo.
[No text to translate]
Tabla de Contenidos¶
- Instalación
- Primeros Pasos
- Conceptos Principales
- Widgets
- Diseños
- Navegación
- Gestión de Estado
- Networking
- Persistencia
- Animaciones
- Integración de Plataforma
- Pruebas
- Depuración
- Despliegue
- Mejores Prácticas
- Resolución de Problemas
The rest of the sections would be translated similarly, maintaining the same structure and technical terms. Would you like me to continue 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¶
```dart // 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### BLoC (Componente de Lógica de Negocio)dart
// 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
// 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### Riverpoddart
// 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 (Redes)dart
// pubspec.yaml
dependencies:
http: ^0.13.0
// services/api_service.dart import 'package:http/http.dart' as http; import 'dart:convert';
class ApiService { Future
// services/api_service.dart import 'package:dio/dio.dart';
class ApiService { final dio = Dio();
Future
// utils/storage.dart import 'package:shared_preferences/shared_preferences.dart';
class Storage {
Future
Future## Persistenciadart
// 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
Future
Future>> getUsers() async {
return await _database.query('users');
}
}
### shared_preferencesdart
class ImplicitAnimation extends StatefulWidget {
@override
_ImplicitAnimationState createState() => _ImplicitAnimationState();
}
class _ImplicitAnimationState extends State
@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,
),
);
}
}
### sqflitedart
class ExplicitAnimation extends StatefulWidget {
@override
_ExplicitAnimationState createState() => _ExplicitAnimationState();
}
class _ExplicitAnimationState extends State
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 2));
_animation = Tween
@override void dispose() { _controller.dispose(); super.dispose(); }
@override
Widget build(BuildContext context) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.green,
);
}
}
## Animacionesdart
// Dart side
import 'package:flutter/services.dart';
const platform = MethodChannel('com.example.myapp/channel');
Future
// 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);
}
}
);
}
}
### Animaciones Implícitasdart
// 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);
});
}
### Animaciones Explícitasdart
// 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);
});
}
## Integración de Plataformadart
// 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');
});
});
}
### MethodChannelbash
Open DevTools from the terminal¶
flutter pub global activate devtools flutter pub global run devtools
Or from VS Code / Android Studio¶
## Pruebasdart
import 'dart:developer' as developer;
void myFunction() {
developer.log('This is a log message', name: 'my.app.category');
}
### Pruebas Unitariasbash
Build an APK¶
flutter build apk
Build an App Bundle¶
flutter build appbundle
### Pruebas de Widgetbash
Build an IPA¶
flutter build ipa
### Pruebas de Integraciónbash
Build for web¶
flutter build web
``## Depuraciónflutter pub deps### DevToolsflutter clean### Registroflutter pub get`para limpiar tus archivos de compilación.
Resumen¶
Flutter es un potente y flexible toolkit de UI para construir aplicaciones multiplataforma de alta calidad. Sus características principales incluyen:
- Desarrollo Rápido: Hot reload te permite ver cambios instantáneamente.
- UI Expresiva: Construye UIs hermosas y personalizadas con un rico conjunto de widgets.
- Rendimiento Nativo: Las aplicaciones Flutter se compilan a código nativo, proporcionando un rendimiento excelente.
- Base de Código Única: Escribe una vez, ejecuta en móvil, web y escritorio.
- Comunidad en Crecimiento: Una comunidad grande y activa proporciona soporte y un rico ecosistema de paquetes.
Flutter es una excelente opción para desarrolladores que quieren construir aplicaciones de alto rendimiento y hermosas para múltiples plataformas con una única base de código.