[Por los muelles] Aleteo. Parte 1. Para desarrolladores de Android

Flutter ya ha escrito muchos artículos. Cada mes se está volviendo más popular. Así que decidí interpretar la documentación oficial de Flutter en un formato conciso de preguntas y respuestas. Creo que muchos, como yo, no tienen suficiente tiempo libre para estudiar en detalle la documentación del marco con el que aún no funcionan.

Si desea comprender para qué sirve este marco y evaluar cuánto esfuerzo tendrá que hacer para usarlo, bienvenido a cat.



Contenido:


  1. Vistas

  2. Intenciones

  3. IU asíncrona

  4. Estructura del proyecto y recursos

  5. Actividades y fragmentos

  6. Diseños

  7. Gestos y manejo de eventos táctiles.

  8. Vistas de lista y adaptadores

  9. Trabajar con texto

  10. Formulario de entrada

  11. Flutter Plugins

  12. Temas

  13. Bases de datos y almacenamiento local.

  14. Notificaciones


Vistas


Pregunta:


¿Cuál es el equivalente de Ver en Flutter?

La respuesta es:


Widget

Diferencias:


Ver: de hecho, lo que estará en la pantalla. Invalidate () se llama para mostrar los cambios.

Widget: una descripción de lo que aparecerá en la pantalla. Para el cambio se crea de nuevo.

Informacion adicional:


Cuando se inicia en Android, View está bajo el capó de Widget. Flutter incluye la biblioteca de componentes de material . Contiene widgets que implementan pautas de diseño de materiales .

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 is Awesome!".

 import 'package:flutter/material.dart'; 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> { //   String textToShow = "  Flutter"; void _updateText() { setState(() { //   textToShow = "Flutter !"; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center(child: Text(textToShow)), floatingActionButton: FloatingActionButton( onPressed: _updateText, tooltip: ' ', child: Icon(Icons.update), ), ); } } 

Pregunta:


¿Cómo diseñar una pantalla con widgets? ¿Dónde está el archivo de diseño XML?

La respuesta es:


Flutter no tiene diseño XML para pantallas. 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: MaterialButton( onPressed: () {}, 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 Android, puede hacer addView () o removeView () en un ViewGroup. En Flutter no es posible, porque los widgets no cambian. Solo su condición puede cambiar.

Un ejemplo:


Cómo cambiar Texto a Botón haciendo clic en FloatingActionButton.

 import 'package:flutter/material.dart'; 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> { //     bool toggle = true; void _toggle() { setState(() { toggle = !toggle; }); } _getToggleChild() { if (toggle) { return Text('Toggle One'); } else { return MaterialButton(onPressed: () {}, child: Text('Toggle Two')); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: _getToggleChild(), ), floatingActionButton: FloatingActionButton( onPressed: _toggle, tooltip: 'Update Text', child: Icon(Icons.update), ), ); } } 

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 Android, puede crear animaciones en XML o animar la vista usando animate (). 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.

 import 'package:flutter/material.dart'; void main() { runApp(FadeAppTest()); } class FadeAppTest extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Fade Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyFadeTest(title: 'Fade Demo'), ); } } class MyFadeTest extends StatefulWidget { MyFadeTest({Key key, this.title}) : super(key: key); final String title; @override _MyFadeTest createState() => _MyFadeTest(); } class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin { AnimationController controller; CurvedAnimation curve; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Container( child: FadeTransition( opacity: curve, child: FlutterLogo( size: 100.0, )))), floatingActionButton: FloatingActionButton( tooltip: 'Fade', child: Icon(Icons.brush), onPressed: () { controller.forward(); }, ), ); } } 

Pregunta:


¿Cómo usar Canvas ?

La respuesta es:


Android y Flutter tienen la misma API para Canvas, ya que usan el mismo motor Skia de bajo nivel.

Diferencias:


No

Informacion adicional:


Flutter tiene dos clases para dibujar en Canvas: CustomPaint y CustomPainter . El segundo implementa su algoritmo de renderizado.

Lea más aquí: StackOverflow

Un ejemplo:


 import 'package:flutter/material.dart'; void main() => runApp(MaterialApp(home: DemoApp())); class DemoApp extends StatelessWidget { Widget build(BuildContext context) => Scaffold(body: Signature()); } 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), ); } } 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; } 

Pregunta:


¿Cómo crear widgets personalizados?

La respuesta es:


Componga widgets dentro de uno (en lugar de herencia).

Diferencias:


En Android, podemos heredar de la Vista que nos interesa y agregar nuestra propia lógica. En Flutter, esto es similar a un ViewGroup, solo el 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"), ); } 

Intenciones


Pregunta:


¿Cuál es el análogo de Intención en Flutter?

La respuesta es:


El no esta ahi. Para navegar entre pantallas, se utilizan las clases Navegador y Ruta .

Para interactuar con componentes externos (por ejemplo, una cámara o un selector de archivos), puede usar complementos o integración nativa en cada plataforma. Obtenga más información sobre la integración nativa: desarrollo de paquetes y complementos .

Diferencias:


Flutter no tiene tal cosa como actividad y fragmento. Hay Navigator (Navigator) y Rutas (rutas). La aplicación Flutter se asemeja a una aplicación de una sola actividad, donde diferentes pantallas representan diferentes fragmentos, y el FragmentManager los controla. Navigator es similar al FragmentManager en principio. Puede hacer push () o pop () a la ruta que especifique. La ruta es un tipo de fragmento, pero en Flutter es habitual compararlo con una pantalla o página.

En Android, describimos todas las actividades entre las que podemos navegar en AndroidManifest.xml.

Flutter tiene dos formas:

  • Describa un mapa llamado Ruta (MaterialApp)
  • Navega directamente a Ruta (WidgetApp).

Un ejemplo:


 void main() { runApp(MaterialApp( home: MyAppHome(), // becomes the route named '/' routes: <String, WidgetBuilder> { '/a': (BuildContext context) => MyPage(title: 'page A'), '/b': (BuildContext context) => MyPage(title: 'page B'), '/c': (BuildContext context) => MyPage(title: 'page C'), }, )); } Navigator.of(context).pushNamed('/b'); 

Pregunta:


¿Cómo procesar intentos provenientes de otras aplicaciones?

La respuesta es:


Interactuando con la capa de Android de la aplicación a través de MethodChannel .

Un ejemplo:


Escribimos intent-filter en AndroidManifest.xml:

 <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- ... --> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> 

Procesamos la intención en MainActivity y llamamos al código desde Flutter a través de MethodChannel:

 package com.example.shared; import android.content.Intent; import android.os.Bundle; import java.nio.ByteBuffer; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private String sharedText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } } new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { if (call.method.contentEquals("getSharedText")) { result.success(sharedText); sharedText = null; } } }); } void handleSendText(Intent intent) { sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); } } 

Solicitamos datos cuando el widget comienza a dibujarse:

 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample Shared App Handler', 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> { static const platform = const MethodChannel('app.channel.shared.data'); String dataShared = "No data"; @override void initState() { super.initState(); getSharedText(); } @override Widget build(BuildContext context) { return Scaffold(body: Center(child: Text(dataShared))); } getSharedText() async { var sharedData = await platform.invokeMethod("getSharedText"); if (sharedData != null) { setState(() { dataShared = sharedData; }); } } } 

Pregunta:


¿Cuál es el análogo de startActivityForResult () ?

La respuesta es:


La palabra clave aguarda y el resultado de una clase Futuro .

Diferencias:


Después de llamar a startActivityForResult () en Android, necesitamos implementar el procesamiento en onActivityResult (). Flutter no necesita implementar nada, porque El método de navegador push () devuelve un objeto Future.

Un ejemplo:


 Map coordinates = await Navigator.of(context).pushNamed('/location'); 

Y cuando tengamos las coordenadas en la pantalla '/ ubicación', haga pop ():

 Navigator.of(context).pop({"lat":43.821757,"long":-79.226392}); 

IU asíncrona


Pregunta:


¿Cuál es el análogo de runOnUiThread () 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 de 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 Android, puede usar AsyncTask. Debe implementar onPreExecute () , doInBackground () , onPostExecute () en él . 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); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // The entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; }   : import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:isolate'; 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() { if (widgets.length == 0) { return true; } return false; } 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 { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // the entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; } } 

Pregunta:


¿Cuál es el equivalente de Flutter de OkHttp ?

La respuesta es:


Flutter tiene su propio paquete HTTP .

Informacion adicional:


Hasta ahora, no todas las características OkHttp se han implementado en el paquete HTTP, por lo que muchas de las características que faltan se abstraen y puede implementarlas usted mismo según sea necesario.

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 Android, los recursos tienen una carpeta res y tienen activos. Flutter solo tiene activos. La carpeta de activos se puede ubicar en cualquier parte del proyecto, lo más importante es escribir la ruta en el archivo pubspec.yaml.

Informacion adicional:


Comparación de los tamaños de los recursos gráficos en Android y Flutter.
Calificador de densidad de AndroidRelación de píxeles de aleteo
ldpi0.75x
mdpi1.0x
hdpi1.5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
Flutter usa AssetManager o clases especializadas que comienzan con Asset para usar recursos en el código.

Un ejemplo:


AssetManager:

 val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png") 

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

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 el análogo del archivo gradle? ¿Cómo agregar dependencias?

La respuesta es:


pubspec.yaml.

Informacion adicional:


Flutter delega el ensamblaje a los creadores nativos de Android e iOS. Vea una lista de todas las bibliotecas populares para Flutter en Pub .

Actividades y fragmentos


Pregunta:


¿Cuál es el equivalente de Actividad y Fragmento en Flutter?

La respuesta es:


Todo en Flutter son widgets. Los widgets juegan el papel de la actividad y los fragmentos para trabajar con la interfaz de usuario. Y el papel de la navegación, como se menciona en el párrafo sobre navegación, es Navegador y Ruta.

Informacion adicional:


Flutter para desarrolladores de Android: cómo diseñar una IU de actividad en Flutter .

Pregunta:


¿Cómo manejar los eventos del ciclo de vida?

La respuesta es:


Usando el método WidgetsBinding y didChangeAppLifecycleState () .

Informacion adicional:


Flutter usa FlutterActivity en código nativo, y el motor Flutter hace que los cambios de estado de procesamiento sean lo más discretos posible. Pero si aún necesita hacer algún trabajo dependiendo del estado, el ciclo de vida es ligeramente diferente:

  • inactivo: este método es solo en iOS, en Android no hay análogo;
  • en pausa: similar a onPause () en Android;
  • resumido: similar a onPostResume () en Android;
  • suspensión: similar a onStop 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 análogo de LinearLayout ?

La respuesta es:


Fila para horizontal, columna para vertical.

Informacion adicional:


Flutter para desarrolladores de Android: ¿Cómo diseñar LinearLayout en Flutter?

Un ejemplo:


 @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Column One'), Text('Column Two'), Text('Column Three'), Text('Column Four'), ], ); } 

Pregunta:


¿Cuál es el equivalente de RelativeLayout ?

La respuesta es:


Pila de widgets.

Más detalles:

Stackoverflow

Pregunta:


¿Cuál es el análogo de ScrollView ?

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'), ], ); } 

Pregunta:


¿Cómo manejar las transiciones entre retrato y paisaje?

La respuesta es:


FlutterView maneja los flips si AndroidManifest.xml contiene
android: configChanges = "orientación | tamaño de pantalla"

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(); } }, ), )); } } 

Vistas de lista y adaptadores


Pregunta:


¿Cuál es el análogo de ListView en Flutter?

La respuesta es:


ListView

Diferencias:


Flutter no tiene que pensar en limpiar y reutilizar elementos (que es lo que hace ListView / RecyclerView en Android, usando el patrón ViewHolder).

Un ejemplo:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @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> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i"))); } return widgets; } } 

Pregunta:


¿Cómo averiguar en qué elemento se hizo clic?

La respuesta es:


Envolver un elemento en un GestureDetector .

Un ejemplo:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @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> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { print('row tapped'); }, )); } return widgets; } } 

Pregunta:


¿Cómo actualizar dinámicamente un ListView ?

La respuesta es:


Si tiene un pequeño conjunto de datos, esto se puede hacer a través de setState () . Si el conjunto de datos es grande, entonces a través de ListView.Builder , que es un análogo de RecyclerView .

Un ejemplo:


Usando setState () :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @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 = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: widgets), ); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets = List.from(widgets); widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 

Usando ListView.Builder :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @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 = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @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 GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 

Trabajar con texto


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
  • decorationColor;
  • decorationStyle;
  • fontFamily;
  • fontSize;
  • fontStyle;
  • fontWeight;
  • hashCode;
  • height;
  • inherit;
  • letterSpacing;
  • textBaseline;
  • wordSpacing.


: 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:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @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> { String _errorText; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: TextField( onSubmitted: (String text) { setState(() { if (!isEmail(text)) { _errorText = 'Error: This is not an email'; } else { _errorText = null; } }); }, decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()), ), ), ); } _getErrorText() { return _errorText; } bool isEmail(String em) { String emailRegexp = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; RegExp regExp = RegExp(emailRegexp); return regExp.hasMatch(em); } } 

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 .

:


NDK?

La respuesta es:


NDK- Flutter. Flutter .

Themes


:


(Theme) ?

La respuesta es:


MaterialApp WidgetApp .

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(), ); } } 


:


Shared Preferences?

La respuesta es:


Shared_Preferences plugin ( NSUserDefaults iOS ).

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); } 

:


SQLite Flutter?

La respuesta es:


SQFlite .

Notificaciones


:


push-?

La respuesta es:


Firebase_Messaging .

Conclusión


. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . Eso es todo para mí. Google Play!

Source: https://habr.com/ru/post/442432/


All Articles