Después de un largo descanso, continuaré hablando sobre el popular marco Flutter en un formato de preguntas y respuestas. Puede encontrar el primer artículo para desarrolladores de Android
aquí , y hoy habrá material útil para desarrolladores para iOS.
Si tiene poco tiempo para un estudio independiente y profundo de la documentación, pero desea comprender qué Flutter es bueno y cómo usarlo, eche un vistazo debajo del gato.
Aleteo Parte 1. Para desarrolladores de AndroidAleteo Parte 2. Para desarrolladores de iOSAleteo Parte 3. Para desarrolladores nativos de ReactAleteo Parte 4. Para desarrolladores webAleteo Parte 5. Para desarrolladores de Xamarin.Forms
Contenido:
- Vistas
- La navegación
- Roscado y asincronía
- Estructura del proyecto y recursos
- ViewControllers
- Diseños
- Gestos y manejo de eventos táctiles
- Estilo de aplicación
- Formulario de entrada
- Flutter Plugins
- Bases de datos y almacenamiento local.
- Notificaciones
Vistas
Pregunta:
¿Qué es el
análogo UIView en Flutter?
La respuesta es:
WidgetDiferencias:
UIView es en realidad lo que estará en la pantalla. Se llama a SetNeedsDisplay () para mostrar los cambios.
Widget : una descripción de lo que aparecerá en la pantalla. Para el cambio se crea de nuevo.
Informacion adicional:
Flutter incluye la biblioteca de
widgets de Cupertino . Contiene widgets que implementan
las pautas de diseño de Apple .
Pregunta:
¿Cómo actualizar la visualización de widgets?
La respuesta es:
Usando
StatefulWidget y su
estado . Flutter tiene 2 tipos de widgets:
StatelessWidget y
StatefulWidget . Funcionan de la misma manera, la única diferencia está en el estado de representación.
Diferencias:
StatelessWidget tiene un estado inmutable. Adecuado para mostrar texto, logotipo, etc. Es decir Si el elemento en la pantalla no debe cambiar durante todo el tiempo de visualización, entonces le conviene. También se puede usar como contenedor para widgets con estado.
StatefulWidget tiene el estado State, que almacena información sobre el estado actual. Si desea cambiar un elemento en la pantalla al realizar alguna acción (una respuesta vino del servidor, el usuario hizo clic en un botón, etc.), esta es su opción.
Un ejemplo:
1) StatelessWidget - Texto
Text( 'I like Flutter!', style: TextStyle(fontWeight: FontWeight.bold), );
2) StatefulWidget: cuando hace clic en el botón (FloatingActionButton), el texto en el widget de texto cambia de
Me gusta Flutter a
Flutter es impresionante. import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pregunta:
¿Cómo diseñar una pantalla con widgets? ¿Dónde está el
guión gráfico ?
La respuesta es:
Flutter no tiene
Storyboard . Todo está compuesto en el árbol de widgets directamente en el código.
Un ejemplo:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: CupertinoButton( onPressed: () { setState(() { _pressedCount += 1; }); }, child: Text('Hello'), padding: EdgeInsets.only(left: 10.0, right: 10.0), ), ), ); }
Todos los widgets predeterminados en Flutter se pueden ver en el
catálogo de widgets .
Pregunta:
¿Cómo agregar o eliminar un componente en el diseño mientras se ejecuta la aplicación?
La respuesta es:
A través de una función que devolverá el widget deseado según el estado.
Diferencias:
En iOS, puede hacer addSubview () o removeFromSuperview (). En Flutter no es posible porque los widgets no cambian. Solo su condición puede cambiar.
Un ejemplo:
Cambie Texto a Botón haciendo clic en FloatingActionButton.
class SampleApp extends StatelessWidget {
Pregunta:
¿Cómo animar widgets?
La respuesta es:
Usando la clase
AnimationController , que es el descendiente de la clase abstracta
Animation <T> . Además de comenzar la animación, puede pausarla, rebobinarla, detenerla y reproducirla en la dirección opuesta. Funciona con
Ticker , que informa sobre un nuevo dibujo de la pantalla.
Diferencias:
En iOS, puede animar una vista usando animar (con Duración: animaciones :). En Flutter, la animación debe escribirse en código usando AnimationController.
Informacion adicional:
Puede obtener más información en los
widgets de animación y movimiento ,
tutorial de animaciones y
descripción general de animaciones .
Un ejemplo:
Animación desvanecida del logotipo de Flutter.
class SampleApp extends StatelessWidget {
Pregunta:
¿Cómo usar
CoreGraphics ?
La respuesta es:
Flutter usa la API Canvas en el motor de bajo nivel
Skia en lugar de CoreGraphics. Android usa una API de Canvas similar.
Informacion adicional:
Flutter tiene dos clases para dibujar en Canvas:
CustomPaint y
CustomPainter . El segundo implementa su algoritmo de renderizado.
Lea más aquí:
StackOverflowUn ejemplo:
class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; 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); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } }
Pregunta:
¿Cómo cambiar la transparencia de los widgets?
La respuesta es:
Envuelva en el widget de
opacidad .
Diferencias:
En iOS, todas las vistas tienen .opacity o .alpha. En Flutter, esta opción reemplaza el widget de contenedor.
Pregunta:
¿Cómo crear widgets personalizados?
La respuesta es:
Componga widgets dentro de uno (en lugar de herencia).
Diferencias:
En iOS, puede heredar de la vista que nos interesa y agregar su propia lógica. En Flutter, un widget siempre se hereda de StatelessWidget o StatefulWidget. Es decir debe crear un nuevo widget y usarlo como el conjunto de widgets que necesita como parámetros o campos.
Un ejemplo:
class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); }
La navegación
Pregunta:
¿Cómo implementar la navegación entre pantallas en Flutter?
La respuesta es:
Para navegar entre pantallas, se utilizan las clases
Navegador y
Ruta .
Diferencias:
Flutter no tiene conceptos tales como UIViewController y UINavigationController. Hay Navigator (Navigator) y Rutas (rutas). Navigator es similar al UINavigationController en principio. Puede hacer
push () o
pop () a la ruta que especifique. Route es una especie de UIViewController, pero en Flutter es habitual compararlo con una pantalla o página.
Flutter tiene dos métodos de navegación:
- Describa un mapa con nombres de ruta
- Navega directamente a la ruta.
Un ejemplo:
void main() { runApp(CupertinoApp( home: MyAppHome(),
Pregunta:
¿Cómo navegar a una aplicación de terceros?
La respuesta es:
O bien interactuando con la capa iOS de la aplicación a través de
MethodChannel , o usando el complemento de
iniciador de URL .
Pregunta:
¿Cómo hacer que pop vuelva en iOS ViewController?
La respuesta es:
Llamando a SystemNavigator.pop ().
Informacion adicional:
SystemNavigator.pop () del código Dart llama al siguiente código en iOS:
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; if ([viewController isKindOfClass:[UINavigationController class]]) { [((UINavigationController*)viewController) popViewControllerAnimated:NO]; }
Si esto no es lo que necesita, puede hacer su implementación a través de
MethodChannel .
Roscado y asincronía
Pregunta:
¿Cómo escribir código asincrónico en Flutter?
La respuesta es:
Dart implementa un modelo de ejecución de subproceso único que se ejecuta en
aislamientos . La ejecución asincrónica usa async / await, con la que puede estar familiarizado desde C #, JavaScript o las rutinas Kotlin.
Un ejemplo:
Cumplir la solicitud y devolver el resultado para actualizar la interfaz de usuario:
loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); }
Cuando se recibe la respuesta a la solicitud, debe llamar al método
setState () para volver a dibujar el árbol de widgets con los nuevos datos.
Un ejemplo:
Cargando y actualizando datos en un
ListView :
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return Padding( padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}") ); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
Pregunta:
¿Cómo ejecutar código en un hilo de fondo?
La respuesta es:
Como se mencionó anteriormente, utilizando async / await y aislamiento (Isolate).
Diferencias:
Fuera de la caja en iOS, puede usar Operation con una posible redefinición de métodos. En Flutter "fuera de la caja" solo necesita usar async / wait, Dart se encargará del resto.
Un ejemplo:
Aquí el método dataLoader () está aislado. De forma aislada, puede ejecutar operaciones pesadas como analizar JSON grandes, cifrado, procesamiento de imágenes, etc.
loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort);
Pregunta:
¿Cómo hacer solicitudes de red en Flutter?
La respuesta es:
Flutter tiene su propio
paquete HTTP .
Un ejemplo:
Para usar el paquete HTTP, agréguelo como una dependencia en pubspec.yaml:
dependencies: ... http: ^0.11.3+16
Para ejecutar la solicitud, llame en espera en la función asincrónica http.get ():
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; [...] loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
Pregunta:
¿Cómo mostrar el progreso?
La respuesta es:
Usando el widget
ProgressIndicator .
Un ejemplo:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
Estructura del proyecto y recursos
Pregunta:
¿Dónde almacenar recursos de diferentes resoluciones?
La respuesta es:
En activos.
Diferencias:
En iOS, los recursos gráficos tienen Images.xcasset, que se encuentran en la carpeta de activos. Flutter solo tiene activos. La carpeta de recursos se puede ubicar en cualquier parte del proyecto, lo más importante es escribir la ruta en el archivo pubspec.yaml.
Informacion adicional:
Los tamaños de los recursos gráficos en iOS y Flutter son idénticos y siguen el formato basado en la densidad.
Ubicación del recurso:
images/my_icon.png // Base: 1.0x image images/2.0x/my_icon.png // 2.0x image images/3.0x/my_icon.png // 3.0x image
Ruta en el archivo pubspec.yaml:
assets: - images/my_icon.png
Usando
AssetImage :
return AssetImage("images/a_dot_burr.jpeg");
Usando el activo directamente:
@override Widget build(BuildContext context) { return Image.asset("images/my_image.png"); }
Pregunta:
¿Dónde almacenar cadenas? ¿Cómo localizarlos?
La respuesta es:
Almacenar en campos estáticos. Localizar usando el
paquete intl .
Un ejemplo:
class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage)
Pregunta:
¿Cuál es la contraparte de CocoaPods? ¿Cómo agregar dependencias?
La respuesta es:
pubspec.yaml.
Informacion adicional:
Flutter delega la compilación a constructores nativos de Android e iOS. Vea una lista de todas las bibliotecas populares para Flutter en
Pub .
ViewControllers
Pregunta:
¿Cuál es el equivalente de
ViewController en Flutter?
La respuesta es:
Todo en Flutter son widgets. El papel de ViewController para trabajar con la interfaz de usuario lo juegan los widgets. Y el papel de la navegación, como se menciona en el párrafo sobre navegación, es Navegador y Ruta.
Pregunta:
¿Cómo manejar los eventos del ciclo de vida?
La respuesta es:
Usando el
método WidgetsBinding y
didChangeAppLifecycleState () .
Informacion adicional:
Flutter usa FlutterAppDelegate en código nativo, y el motor Flutter hace que el manejo de los cambios de estado sea lo más discreto posible. Pero si aún necesita hacer algún trabajo dependiendo del estado, el ciclo de vida es ligeramente diferente:
- inactivo: la aplicación está inactiva y no recibe información del usuario. Este estado es solo en iOS, en Android no hay análogo;
- en pausa: la aplicación es actualmente invisible para el usuario, no responde a la entrada del usuario, pero funciona en segundo plano;
- reanudado: la aplicación es visible y responde a la entrada del usuario;
- suspensión - aplicación en proceso de detención. Este estado es solo en Android, en iOS no hay análogo.
Esto se describe con más detalle en la
documentación de AppLifecycleStatus .
Un ejemplo:
import 'package:flutter/widgets.dart'; class LifecycleWatcher extends StatefulWidget { @override _LifecycleWatcherState createState() => _LifecycleWatcherState(); } class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver { AppLifecycleState _lastLifecycleState; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { setState(() { _lastLifecycleState = state; }); } @override Widget build(BuildContext context) { if (_lastLifecycleState == null) return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr); return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.', textDirection: TextDirection.ltr); } } void main() { runApp(Center(child: LifecycleWatcher())); }
Diseños
Pregunta:
¿Cuál es el equivalente de
UITableView y
UICollectionView ?
La respuesta es:
ListViewUn ejemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pregunta:
¿Cómo sé en qué elemento de la lista se hizo clic?
La respuesta es:
El widget, que es un elemento de la lista, debe manejar el clic en él.
Diferencias:
En iOS, el método tableView: didSelectRowAtIndexPath: es el responsable de esto. En Flutter, el elemento de la lista debe estar envuelto en un widget que maneja los clics, como el
GestureDetector .
Pregunta:
¿Cómo actualizar dinámicamente un
ListView ?
La respuesta es:
Actualice la lista de datos y llame a setState ().
Diferencias:
En iOS, debe actualizar los datos y llamar al método reloadData. En Flutter, después de setState (), el widget se volverá a dibujar de nuevo.
Un ejemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Informacion adicional:
Para crear una lista, se recomienda usar
ListView.Builder .
Un ejemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pregunta:
¿Cuál es el análogo de
UIScrollView ?
La respuesta es:
ListView con widgets.
Un ejemplo:
@override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); }
Informacion adicional:
Más detalles
aquí .
Gestos y manejo de eventos táctiles
Pregunta:
¿Cómo agregar onClick listener para widget en Flutter?
La respuesta es:
Si el widget admite clics, entonces en onPressed (). Si no, entonces en onTap ().
Un ejemplo:
En onPressed ():
@override Widget build(BuildContext context) { return RaisedButton( onPressed: () { print("click"); }, child: Text("Button"), ); }
En onTap ():
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), ), ); } }
Pregunta:
¿Cómo manejar otros gestos en widgets?
La respuesta es:
Usando el
GestureDetector . Pueden manejar las siguientes acciones:
Toque
Doble toque
Pulsación larga
Arrastre vertical
Arrastre horizontal
Un ejemplo:
Procesamiento en DoubleTap:
AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), ), ); } }
Estilo de aplicación
Pregunta:
¿Cómo usar el tema (Theme) en la aplicación?
La respuesta es:
Usando el widget MaterialApp o WidgetApp como la raíz en la aplicación.
Un ejemplo:
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, textSelectionColor: Colors.red ), home: SampleAppPage(), ); } }
Pregunta:
¿Cómo usar fuentes personalizadas?
La respuesta es:
Solo necesita poner el archivo de fuente en la carpeta (piense en el nombre usted mismo) e indique la ruta en pubspec.yaml.
Un ejemplo:
fonts: - family: MyCustomFont fonts: - asset: fonts/MyCustomFont.ttf - style: italic
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: Text( 'This is a custom font text', style: TextStyle(fontFamily: 'MyCustomFont'), ), ), ); }
Pregunta:
¿Cómo diseñar widgets de texto?
La respuesta es:
Usando parámetros:
- color
- decoracion
- decoraciónColor;
- decoraciónEstilo;
- fontFamily;
- fontSize;
- fontStyle;
- fontWeight;
- hashCode;
- altura
- heredar
- letterSpacing;
- textBaseline;
- wordSpacing.
Formulario de entrada
Pregunta:
¿Cómo obtener el resultado de entrada del usuario?
La respuesta es:
Usando
TextEditingController .
Un ejemplo:
class _MyFormState extends State<MyForm> {
:
Retrieve the value of a text field .
:
hint
TextInput ?
La respuesta es:
InputDecoration , .
Un ejemplo:
body: Center( child: TextField( decoration: InputDecoration(hintText: "This is a hint"), ), )
:
?
La respuesta es:
—
InputDecoration .
Un ejemplo:
class SampleApp extends StatelessWidget {
Flutter
:
GPS?
La respuesta es:
geolocator .
:
?
La respuesta es:
image_picker .
:
Facebook?
La respuesta es:
flutter_facebook_login .
:
Firebase?
La respuesta es:
Firebase
Flutter first party plugins :
:
() ?
La respuesta es:
Flutter EventBus . :
developing packages and plugins .
:
UserDefault?
La respuesta es:
Shared_Preferences plugin ( Shared Preferences Android ).
Un ejemplo:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); }
:
Core Data ?
La respuesta es:
SQFlite .
:
push-?
La respuesta es:
Firebase_Messaging .
Conclusión
. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Apple Store!