Flutter para desarrolladores de SwiftUI
Aprende cómo aplicar los conocimientos de desarrollador de SwiftUI al compilar aplicaciones Flutter.
Los desarrolladores de SwiftUI que deseen escribir aplicaciones móviles utilizando Flutter deberían revisar esta guía. Explica cómo aplicar los conocimientos existentes de SwiftUI a Flutter.
Flutter es un framework para compilar aplicaciones multiplataforma que utiliza el lenguaje de programación Dart. Para comprender algunas diferencias entre la programación con Dart y la programación con Swift, consulta Aprender Dart como desarrollador de Swift (Learning Dart as a Swift Developer) y Concurrencia en Flutter para desarrolladores de Swift (Flutter concurrency for Swift developers).
Tus conocimientos y experiencia en SwiftUI son sumamente valiosos al construir con Flutter.
Flutter también realiza una serie de adaptaciones en el comportamiento de la aplicación cuando se ejecuta en iOS y macOS. Para saber cómo, consulta Adaptaciones de la plataforma (Platform adaptations).
Este documento se puede utilizar como un recetario (cookbook) para saltar de un lado a otro y encontrar las preguntas que sean más relevantes para tus necesidades. Esta guía incorpora código de ejemplo. Al usar el botón "Open in DartPad" que aparece al pasar el cursor o enfocar, puedes abrir y ejecutar algunos de los ejemplos en DartPad.
Resumen
#Como introducción, mira el siguiente video. Describe a grandes rasgos cómo funciona Flutter en iOS y cómo usar Flutter para compilar aplicaciones de iOS.
El código de Flutter y SwiftUI describe cómo se ve y funciona la UI. Los desarrolladores llaman a este tipo de código un framework declarativo.
Views vs. Widgets
#SwiftUI representa componentes de UI como views (vistas). Configuras las vistas usando modifiers (modificadores).
Text("Hello, World!") // <-- This is a View
.padding(10) // <-- This is a modifier of that View
Flutter representa los componentes de UI como widgets.
Tanto las vistas como los widgets solo existen hasta que necesitan ser cambiados. Estos lenguajes llaman a esta propiedad inmutabilidad. SwiftUI representa la propiedad de un componente de UI como un modificador de View. Por el contrario, Flutter utiliza widgets tanto para los componentes de UI como para sus propiedades.
Padding( // <-- This is a Widget
padding: EdgeInsets.all(10.0), // <-- So is this
child: Text("Hello, World!"), // <-- This, too
)));
Para componer diseños, tanto SwiftUI como Flutter anidan componentes de UI entre sí. SwiftUI anida Views mientras que Flutter anida Widgets.
Proceso de diseño
#SwiftUI distribuye las vistas mediante el siguiente proceso:
- La vista padre propone un tamaño a su vista hija.
-
All subsequent child views:
- propone un tamaño a la vista de su hijo
- le pregunta a esa vista hija qué tamaño desea
- Cada vista padre renderiza su vista hija en el tamaño devuelto.
Flutter difiere un poco con su proceso:
-
El widget padre pasa restricciones a sus hijos. Las restricciones incluyen valores mínimos y máximos para la altura y el ancho.
-
El hijo intenta decidir su tamaño. Repite el mismo proceso con su propia lista de hijos:
- Informa a su hijo sobre las restricciones de este.
- Le pregunta a su hijo qué tamaño desea tener.
-
El padre distribuye al hijo.
- Si el tamaño solicitado se ajusta a las restricciones, el padre utiliza esa dimensión.
- Si el tamaño solicitado no se ajusta a las restricciones, el padre limita la altura, el ancho o ambos para que se ajusten a sus restricciones.
Flutter difiere de SwiftUI porque el componente padre puede sobrescribir el tamaño deseado del hijo. El widget no puede tener el tamaño que quiera. Tampoco puede conocer ni decidir su posición en la pantalla, ya que su padre toma esa decisión.
Para forzar a un widget hijo a renderizarse a un tamaño específico, el padre debe establecer restricciones estrictas (tight constraints). Una restricción se vuelve estricta cuando el valor de tamaño mínimo de su restricción es igual a su valor de tamaño máximo.
En SwiftUI, las vistas pueden expandirse al espacio disponible o limitar su tamaño al de su contenido. Los widgets de Flutter se comportan de manera similar.
Sin embargo, en Flutter los widgets padres pueden ofrecer restricciones ilimitadas (unbounded constraints). Las restricciones ilimitadas establecen sus valores máximos en infinito.
UnboundedBox(
child: Container(
width: double.infinity, height: double.infinity, color: red),
)
Si el hijo se expande y tiene restricciones ilimitadas, Flutter devuelve una advertencia de desbordamiento (overflow):
UnconstrainedBox(
child: Container(color: red, width: 4000, height: 50),
)
Para aprender cómo funcionan las restricciones en Flutter, consulta Entendiendo las restricciones (Understanding constraints).
Sistema de diseño
#Debido a que Flutter apunta a múltiples plataformas, tu aplicación no necesita ajustarse a ningún sistema de diseño. Aunque esta guía presenta widgets de Material, tu aplicación Flutter puede usar muchos sistemas de diseño diferentes:
- Widgets de Material personalizados
- Widgets creados por la comunidad
- Tus propios widgets personalizados
- Los widgets de Cupertino que siguen las Directrices de interfaz humana (Human Interface Guidelines) de Apple
Si estás buscando una excelente aplicación de referencia que cuente con un sistema de diseño personalizado, consulta Wonderous.
Conceptos básicos de UI
#Esta sección cubre los conceptos básicos del desarrollo de UI en Flutter y cómo se compara con SwiftUI. Esto incluye cómo comenzar a desarrollar tu aplicación, mostrar texto estático, crear botones, reaccionar a eventos de presión, mostrar listas, cuadrículas y más.
Primeros pasos
#En SwiftUI, utilizas App para iniciar tu aplicación.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
HomePage()
}
}
}
Otra práctica común de SwiftUI coloca el cuerpo de la aplicación dentro de una estructura (struct)
que cumple con el protocolo View de la siguiente manera:
struct HomePage: View {
var body: some View {
Text("Hello, World!")
}
}
Para iniciar tu aplicación Flutter, pasa una instancia de tu aplicación a
la función runApp.
void main() {
runApp(const MyApp());
}
App es un widget. El método build describe la parte de la
interfaz de usuario que representa.
Es común comenzar tu aplicación con una clase WidgetApp,
como CupertinoApp.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// Returns a CupertinoApp that, by default,
// has the look and feel of an iOS app.
return const CupertinoApp(home: HomePage());
}
}
El widget utilizado en HomePage podría comenzar con la clase Scaffold.
Scaffold implementa una estructura de diseño básica para una aplicación.
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(body: Center(child: Text('Hello, World!')));
}
}
Nota cómo Flutter utiliza el widget Center.
SwiftUI renderiza los contenidos de una vista en su centro de forma predeterminada.
Ese no es siempre el caso con Flutter.
Scaffold no renderiza su widget de cuerpo (body) en el centro de la pantalla.
Para centrar el texto, envúelo en un widget Center.
Para obtener información sobre diferentes widgets y sus comportamientos predeterminados, consulta
el catálogo de widgets (Widget catalog).
Agregar botones
#En SwiftUI, utilizas la estructura Button para crear un botón.
Button("Do something") {
// this closure gets called when your
// button is tapped
}
Para lograr el mismo resultado en Flutter,
utiliza la clase CupertinoButton:
CupertinoButton(
onPressed: () {
// This closure is called when your button is tapped.
},
const Text('Do something'),
),
Flutter te da acceso a una variedad de botones con estilos predefinidos.
La clase CupertinoButton
proviene de la biblioteca Cupertino.
Los widgets de la biblioteca Cupertino utilizan el sistema de diseño de Apple.
Alinear componentes horizontalmente
#En SwiftUI, las vistas de pila (stack views) juegan un papel importante en el diseño de tus layouts. Dos estructuras separadas te permiten crear pilas (stacks):
HStackpara vistas de pila horizontalVStackpara vistas de pila vertical
La siguiente vista de SwiftUI agrega una imagen de un globo terráqueo y texto a una vista de pila horizontal:
HStack {
Image(systemName: "globe")
Text("Hello, world!")
}
Flutter utiliza Row
en lugar de HStack:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [Icon(CupertinoIcons.globe), Text('Hello, world!')],
),
El widget Row requiere un List<Widget> en el parámetro children.
La propiedad mainAxisAlignment le indica a Flutter cómo posicionar a los hijos
si hay espacio adicional. MainAxisAlignment.center posiciona a los hijos en el
centro del eje principal. Para Row, el eje principal es el eje horizontal.
Alinear componentes verticalmente
#Los siguientes ejemplos se basan en los de la sección anterior.
En SwiftUI, utilizas VStack para organizar los componentes en una
columna vertical.
VStack {
Image(systemName: "globe")
Text("Hello, world!")
}
Flutter utiliza el mismo código de Dart del ejemplo anterior,
excepto que cambia Column
por Row:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Icon(CupertinoIcons.globe), Text('Hello, world!')],
),
Mostrar una vista de lista
#En SwiftUI, utilizas el componente base List para mostrar secuencias
de elementos.
Para mostrar una secuencia de objetos de modelo, asegúrate de que el usuario pueda
identificar tus objetos de modelo.
Para hacer que un objeto sea identificable, utiliza el protocolo Identifiable.
struct Person: Identifiable {
var name: String
}
var persons = [
Person(name: "Person 1"),
Person(name: "Person 2"),
Person(name: "Person 3"),
]
struct ListWithPersons: View {
let persons: [Person]
var body: some View {
List {
ForEach(persons) { person in
Text(person.name)
}
}
}
}
Esto se parece a cómo Flutter prefiere construir sus widgets de lista. Flutter no necesita que los elementos de la lista sean identificables. Estableces la cantidad de elementos a mostrar y luego construyes un widget para cada elemento.
class Person {
String name;
Person(this.name);
}
final List<Person> items = [
Person('Person 1'),
Person('Person 2'),
Person('Person 3'),
];
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: Text(items[index].name));
},
),
);
}
}
Flutter tiene algunas advertencias para las listas:
-
El widget
ListViewtiene un método builder. Esto funciona como elForEachdentro de la estructuraListde SwiftUI. -
El parámetro
itemCountdelListViewestablece cuántos elementos muestra elListView. -
El
itemBuildertiene un parámetro index que estará entre cero y uno menos que el itemCount.
El ejemplo anterior devolvió un widget ListTile
para cada elemento.
El widget ListTile incluye propiedades como height y
font-size.
Estas propiedades ayudan a construir una lista. Sin embargo, Flutter te permite devolver
casi cualquier widget que represente tus datos.
Mostrar una cuadrícula
#Al construir cuadrículas (grids) no condicionales en SwiftUI,
utilizas Grid con GridRow.
Grid {
GridRow {
Text("Row 1")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
GridRow {
Text("Row 2")
Image(systemName: "square.and.arrow.down")
Image(systemName: "square.and.arrow.up")
}
}
Para mostrar cuadrículas en Flutter, utiliza el widget GridView
.
Este widget tiene varios constructores. Cada constructor tiene
un objetivo similar, pero utiliza diferentes parámetros de entrada.
El siguiente ejemplo utiliza el inicializador .builder():
const widgets = <Widget>[
Text('Row 1'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
Text('Row 2'),
Icon(CupertinoIcons.arrow_down_square),
Icon(CupertinoIcons.arrow_up_square),
];
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisExtent: 40,
),
itemCount: widgets.length,
itemBuilder: (context, index) => widgets[index],
),
);
}
}
El delegado SliverGridDelegateWithFixedCrossAxisCount determina
varios parámetros que la cuadrícula utiliza para distribuir sus componentes.
Esto incluye el crossAxisCount que dicta la cantidad de elementos
mostrados en cada fila.
La diferencia entre el Grid de SwiftUI y el GridView de Flutter es que Grid
requiere GridRow. GridView utiliza el delegado para decidir cómo la
cuadrícula debe distribuir sus componentes.
Crear una vista de desplazamiento
#En SwiftUI, utilizas ScrollView para crear componentes de desplazamiento
personalizados.
El siguiente ejemplo muestra una serie de instancias de PersonView
de forma desplazable.
ScrollView {
VStack(alignment: .leading) {
ForEach(persons) { person in
PersonView(person: person)
}
}
}
Para crear una vista con desplazamiento, Flutter utiliza SingleChildScrollView.
En el siguiente ejemplo, la función mockPerson simula instancias
de la clase Person para crear el widget PersonView personalizado.
SingleChildScrollView(
child: Column(
children: mockPersons
.map((person) => PersonView(person: person))
.toList(),
),
),
Diseño responsivo y adaptativo
#En SwiftUI, utilizas GeometryReader para crear tamaños de vista relativos.
Por ejemplo, podrías:
- Multiplica
geometry.size.widthpor algún factor para establecer el ancho (width). - Utiliza
GeometryReadercomo un punto de interrupción (breakpoint) para cambiar el diseño de tu aplicación.
También puedes ver si la clase de tamaño (size class) tiene .regular o .compact
utilizando horizontalSizeClass.
Para crear vistas relativas en Flutter, puedes usar una de estas dos opciones:
- Obtener el objeto
BoxConstraintsen la claseLayoutBuilder. - Usar
MediaQuery.of()en tus funciones de construcción para obtener el tamaño y la orientación de tu aplicación actual.
Para obtener más información, consulta Creación de aplicaciones responsivas y adaptativas (Creating responsive and adaptive apps).
Gestionar el state
#En SwiftUI, utilizas el envoltorio de propiedad @State para representar el
state interno de una vista de SwiftUI.
struct ContentView: View {
@State private var counter = 0;
var body: some View {
VStack{
Button("+") { counter+=1 }
Text(String(counter))
}
}}
SwiftUI también incluye varias opciones para una gestión del state
más compleja, como el protocolo ObservableObject.
Flutter gestiona el state local utilizando un StatefulWidget.
Implementa un widget stateful con las siguientes dos clases:
- una subclase de
StatefulWidget - una subclase de
State
El objeto State almacena el state del widget.
Para cambiar el state de un widget, llama a setState() desde la subclase State
para indicarle al framework que vuelva a dibujar el widget.
El siguiente ejemplo muestra parte de una aplicación de contador:
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$_counter'),
TextButton(
onPressed: () => setState(() {
_counter++;
}),
child: const Text('+'),
),
],
),
),
);
}
}
Para conocer más formas de gestionar el state, consulta Gestión del state (State management).
Animaciones
#Existen dos tipos principales de animaciones de UI.
- Implícitas, que animan desde un valor actual a un nuevo objetivo.
- Explícitas, que animan cuando se les solicita.
Animación implícita
#SwiftUI y Flutter adoptan un enfoque similar para la animación.
En ambos frameworks, especificas parámetros como duration y curve.
En SwiftUI, utilizas el modificador animate() para manejar la animación
implícita.
Button("Tap me!"){
angle += 45
}
.rotationEffect(.degrees(angle))
.animation(.easeIn(duration: 1))
Flutter incluye widgets para animación implícita.
Esto simplifica la animación de widgets comunes.
Flutter nombra estos widgets con el siguiente formato: AnimatedFoo.
For example: To rotate a button, use the AnimatedRotation
class.
This animates the Transform.rotate widget.
AnimatedRotation(
duration: const Duration(seconds: 1),
turns: turns,
curve: Curves.easeIn,
TextButton(
onPressed: () {
setState(() {
turns += .125;
});
},
const Text('Tap me!'),
),
),
Flutter allows you to create custom implicit animations.
To compose a new animated widget, use the TweenAnimationBuilder.
Animación explícita
#For explicit animations, SwiftUI uses the withAnimation() function.
Flutter includes explicitly animated widgets with names formatted
like FooTransition.
One example would be the RotationTransition
class.
Flutter also allows you to create a custom explicit animation using
AnimatedWidget or AnimatedBuilder.
To learn more about animations in Flutter, see Animations overview.
Dibujar en la pantalla
#In SwiftUI, you use CoreGraphics to draw lines and shapes to the
screen.
Flutter tiene una API basada en la clase Canvas,
con dos clases que te ayudan a dibujar:
-
CustomPaintque requiere un pintor (painter):dartCustomPaint( painter: SignaturePainter(_points), size: Size.infinite, ), -
CustomPainterque implementa tu algoritmo para dibujar en el canvas.dartclass SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset?> points; @override void paint(Canvas canvas, Size size) { final Paint paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) { canvas.drawLine(points[i]!, points[i + 1]!, paint); } } } @override bool shouldRepaint(SignaturePainter oldDelegate) => oldDelegate.points != points; }
Navegación
#This section explains how to navigate between pages of an app, the push and pop mechanism, and more.
Navegar entre páginas
#Developers build iOS and macOS apps with different pages called navigation routes.
In SwiftUI, the NavigationStack represents this stack of pages.
The following example creates an app that displays a list of persons. To display a person's details in a new navigation link, tap on that person.
NavigationStack(path: $path) {
List {
ForEach(persons) { person in
NavigationLink(
person.name,
value: person
)
}
}
.navigationDestination(for: Person.self) { person in
PersonView(person: person)
}
}
If you have a small Flutter app without complex linking,
use Navigator
with named routes.
After defining your navigation routes,
call your navigation routes using their names.
-
Name each route in the class passed to the
runApp()function. The following example usesApp:dart// Defines the route name as a constant // so that it's reusable. const detailsPageRouteName = '/details'; class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return CupertinoApp( home: const HomePage(), // The [routes] property defines the available named routes // and the widgets to build when navigating to those routes. routes: {detailsPageRouteName: (context) => const DetailsPage()}, ); } }The following sample generates a list of persons using
mockPersons(). Tapping a person pushes the person's detail page to theNavigatorusingpushNamed().dartListView.builder( itemCount: mockPersons.length, itemBuilder: (context, index) { final person = mockPersons.elementAt(index); final age = '${person.age} years old'; return ListTile( title: Text(person.name), subtitle: Text(age), trailing: const Icon(Icons.arrow_forward_ios), onTap: () { // When a [ListTile] that represents a person is // tapped, push the detailsPageRouteName route // to the Navigator and pass the person's instance // to the route. Navigator.of( context, ).pushNamed(detailsPageRouteName, arguments: person); }, ); }, ), -
Define the
DetailsPagewidget that displays the details of each person. In Flutter, you can pass arguments into the widget when navigating to the new route. Extract the arguments usingModalRoute.of():dartclass DetailsPage extends StatelessWidget { const DetailsPage({super.key}); @override Widget build(BuildContext context) { // Read the person instance from the arguments. final Person person = ModalRoute.of(context)?.settings.arguments as Person; // Extract the age. final age = '${person.age} years old'; return Scaffold( // Display name and age. body: Column(children: [Text(person.name), Text(age)]), ); } }
To create more advanced navigation and routing requirements, use a routing package such as go_router.
To learn more, check out Navigation and routing.
Regresar manualmente (pop back)
#In SwiftUI, you use the dismiss environment value to pop-back to
the previous screen.
Button("Pop back") {
dismiss()
}
In Flutter, use the pop() function of the Navigator class:
TextButton(
onPressed: () {
// This code allows the
// view to pop back to its presenter.
Navigator.of(context).pop();
},
child: const Text('Pop back'),
),
Navegar a otra aplicación
#In SwiftUI, you use the openURL environment variable to open a
URL to another application.
@Environment(\.openURL) private var openUrl
// View code goes here
Button("Open website") {
openUrl(
URL(
string: "https://google.com"
)!
)
}
In Flutter, use the url_launcher
plugin.
CupertinoButton(
onPressed: () async {
await launchUrl(Uri.parse('https://google.com'));
},
const Text('Open website'),
),
Temas, estilos y multimedia
#Puedes estilizar las aplicaciones de Flutter con poco esfuerzo. El estilo incluye cambiar entre temas claros y oscuros, modificar el diseño de tu texto y componentes de UI, y más. Esta sección cubre cómo dar estilo a tus aplicaciones.
Usar el modo oscuro
#In SwiftUI, you call the preferredColorScheme()
function on a View to use dark mode.
En Flutter, puedes controlar el modo claro y oscuro a nivel de aplicación.
Para controlar el modo de brillo (brightness), utiliza la propiedad theme
de la clase App:
const CupertinoApp(
theme: CupertinoThemeData(brightness: Brightness.dark),
home: HomePage(),
);
Estilizar texto
#In SwiftUI, you use modifier functions to style text.
For example, to change the font of a Text string,
use the font() modifier:
Text("Hello, world!")
.font(.system(size: 30, weight: .heavy))
.foregroundColor(.yellow)
Para estilizar texto en Flutter, agrega un widget TextStyle como el valor
del parámetro style del widget Text.
Text(
'Hello, world!',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: CupertinoColors.systemYellow,
),
),
Estilizar botones
#In SwiftUI, you use modifier functions to style buttons.
Button("Do something") {
// Do something when the button is tapped.
}
.font(.system(size: 30, weight: .bold))
.background(Color.yellow)
.foregroundColor(Color.blue)
To style button widgets in Flutter, set the style of its child, or modify properties on the button itself.
En el siguiente ejemplo:
- The
colorproperty ofCupertinoButtonsets itscolor. - The
colorproperty of the childTextwidget sets the button text color.
child: CupertinoButton(
color: CupertinoColors.systemYellow,
onPressed: () {},
child: const Text(
'Do something',
style: TextStyle(
color: CupertinoColors.systemBlue,
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
Usar fuentes personalizadas
#In SwiftUI, you can use a custom font in your app in two steps.
First, add the font file to your SwiftUI project. After adding the file,
use the .font() modifier to apply it to your UI components.
Text("Hello")
.font(
Font.custom(
"BungeeSpice-Regular",
size: 40
)
)
In Flutter, you control your resources with a file
named pubspec.yaml. This file is platform agnostic.
To add a custom font to your project, follow these steps:
-
Create a folder called
fontsin the project's root directory. This optional step helps to organize your fonts. -
Add your
.ttf,.otf, or.ttcfont file into thefontsfolder. Open the
pubspec.yamlfile within the project.Find the
fluttersection.-
Add your custom font(s) under the
fontssection.yamlflutter: fonts: - family: BungeeSpice fonts: - asset: fonts/BungeeSpice-Regular.ttf
After you add the font to your project, you can use it as in the following example:
Text(
'Cupertino',
style: TextStyle(fontSize: 40, fontFamily: 'BungeeSpice'),
),
Empaquetar imágenes en aplicaciones
#In SwiftUI, you first add the image files to Assets.xcassets,
then use the Image view to display the images.
To add images in Flutter, follow a method similar to how you added custom fonts.
Add an
imagesfolder to the root directory.-
Add this asset to the
pubspec.yamlfile.yamlflutter: assets: - images/Blueberries.jpg
After adding your image, display it using the Image widget's
.asset() constructor. This constructor:
- Instancia la imagen dada usando la ruta provista.
- Lee la imagen de los assets empaquetados con tu aplicación.
- Muestra la imagen en la pantalla.
Para revisar un ejemplo completo, consulta la documentación de Image.
Empaquetar videos en aplicaciones
#In SwiftUI, you bundle a local video file with your app in two
steps.
First, you import the AVKit framework, then you instantiate a
VideoPlayer view.
In Flutter, add the video_player plugin to your project. This plugin allows you to create a video player that works on Android, iOS, and on the web from the same codebase.
- Agrega el plugin a tu aplicación y añade el archivo de video a tu proyecto.
- Add the asset to your
pubspec.yamlfile. - Use the
VideoPlayerControllerclass to load and play your video file.
To review a complete walkthrough, check out the video_player example.
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.