Saltar a contenido

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

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'))),
            ),
          ),
        ],
      ),
    );
  }
}
// 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');
// 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().count}'), ), floatingActionButton: FloatingActionButton( onPressed: () => context.read().increment(), child: Icon(Icons.add), ), ); } } ### 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 { CounterBloc() : super(0) { on((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( builder: (context, count) => Text('Count: $count'), ), ), floatingActionButton: FloatingActionButton( onPressed: () => context.read().add(Increment()), child: Icon(Icons.add), ), ); } } ### 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> 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'); } } } ### Paquete httpdart // pubspec.yaml dependencies: dio: ^4.0.0

// services/api_service.dart import 'package:dio/dio.dart';

class ApiService { final dio = Dio();

Future> 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'); } } } ### Paquete diodart // pubspec.yaml dependencies: shared_preferences: ^2.0.0

// utils/storage.dart import 'package:shared_preferences/shared_preferences.dart';

class Storage { Future saveUsername(String username) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('username', username); }

Future getUsername() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString('username'); } } ## 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 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 insertUser(Map user) async { await _database.insert('users', user, conflictAlgorithm: ConflictAlgorithm.replace); }

Future>> getUsers() async { return await _database.query('users'); } } ### shared_preferencesdart class ImplicitAnimation extends StatefulWidget { @override _ImplicitAnimationState createState() => _ImplicitAnimationState(); }

class _ImplicitAnimationState extends State { 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, ), ); } } ### sqflitedart class ExplicitAnimation extends StatefulWidget { @override _ExplicitAnimationState createState() => _ExplicitAnimationState(); }

class _ExplicitAnimationState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation;

@override void initState() { super.initState(); _controller = AnimationController(vsync: this, duration: Duration(seconds: 2)); _animation = Tween(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, ); } } ## Animacionesdart // Dart side import 'package:flutter/services.dart';

const platform = MethodChannel('com.example.myapp/channel');

Future 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: '\)'."; } }

// 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.