Aleteo Pros y contras



Antes que nada, hablemos un poco sobre qué es Flutter. Este es un marco para crear aplicaciones móviles desde Google. Es multiplataforma y le permite compilar el proyecto creado para 3 sistemas operativos:
  • Android
  • iOS
  • Fucsia

Además, para el último sistema operativo, Fuchsia, esta es la única forma de crear una aplicación.
Flutter durante mucho tiempo, desde 2015, se presentó solo en versiones alfa y beta. La primera versión estable se lanzó el 4 de diciembre de 2018.


Flutter es promovido activamente por Google, ganando popularidad gradualmente y, muy probablemente, continuará desplazando a otras herramientas de desarrollo multiplataforma actualmente en uso (React Native, Xamarin), especialmente si Fuchsia está ampliamente distribuido. Dado que Google posiciona este sistema operativo como un reemplazo para Android, tarde o temprano Flutter reemplazará el desarrollo nativo de Android. Por lo tanto, las perspectivas y el desarrollo activo son las principales ventajas de Flutter.


+ Perspectiva y desarrollo activo


Veamos como funciona.


En el lenguaje de programación Dart, se crea una aplicación móvil con una descripción de la interfaz gráfica y toda la lógica de trabajo. El resultado del trabajo se agrega a la aplicación nativa, como imágenes, fuentes y similares (por supuesto, este proceso está automatizado).


Al mismo tiempo, en la parte nativa de la aplicación, se crea una sola pantalla donde se carga la máquina virtual Dart, que ejecuta Flutter.


Tenga en cuenta que uno de los inconvenientes de Flutter se deduce de aquí:


- El paquete de instalación final es más grande, ya que se le agrega la máquina virtual Dart.


Por lo tanto, hay archivos Flutter y hay máquinas virtuales que se agregan dependiendo de qué compilaciones: iOS o Android.


La máquina virtual tiene su propio motor gráfico, dibuja la interfaz de la aplicación con todas las transiciones entre pantallas, diálogos, fragmentos, etc. En esto, el desarrollo bajo Flutter es significativamente diferente del desarrollo con Xamarin y React Native, que usan componentes reales de Android e iOS. En el caso de ellos, es imposible utilizar componentes específicos de la plataforma (si es necesario, debe crear dos versiones de la interfaz de usuario). Al elegir un diseño con Flutter, es suficiente concentrarse en una plataforma (por ejemplo, Android). Al crear un proyecto para iOS, verá una interfaz estándar de Android. Se verá un poco extraño e inesperado, pero bastante funcional (más tarde se puede mejorar la interfaz).


+ Motor de gráficos propio (no es necesario crear una interfaz por separado para Android e iOS)


Ahora sobre las impresiones.


Al portar varias aplicaciones de Android a Flutter, notamos algunas diferencias, que pueden considerarse tanto un más como un menos.


Lo primero que llama la atención es una forma de crear pantallas, que es significativamente diferente de la utilizada en Android e iOS. En Android, la lógica y la interfaz están separadas: la lógica se establece por código, y la interfaz se establece por diseño en xml. En Flutter, todo esto se establece usando código. Aunque aquí se utiliza un estilo especial para la interfaz, los elementos de la interfaz se crean anidados entre sí. Esto es un poco como el diseño, una forma muy similar funciona en React Native. Sin embargo, no hay posibilidad de acceso directo a los elementos. Para cambiar algo en la pantalla, debe actualizar toda la pantalla o usar controladores especiales agregados al widget de antemano durante su creación.


- La interfaz se crea usando código, lo que hace que la línea entre la lógica y el diseño sea mucho más delgada.


Por otro lado, este enfoque facilita la división de pantallas en componentes separados. De hecho, cualquier bloque de elementos de interfaz incrustados se puede mover a un widget separado en solo un par de pasos, y esto es mucho más fácil que crear una Vista personalizada y fragmentos.


+ La interfaz se divide fácilmente en módulos separados


Probablemente valga la pena examinar los dos últimos comentarios. Para hacer esto, escribiremos una aplicación simple que demuestre algunas de las características de Flutter. Esta será una aplicación con una barra de navegación estándar y una barra de pestañas.


Hagamos tres pestañas:


1) Primero: con texto y controles deslizantes para ajustar el tamaño y el color del texto
2) Agregue una imagen descargable a la segunda (con indicador de progreso)
3) En tercer lugar, una lista de ejemplo




Supongamos también que inicialmente no dividimos la interfaz de la aplicación en pestañas separadas. En Flutter, puede implementar esta pantalla sin usar fragmentos. Por supuesto, tal partición sigue siendo deseable, pero supongamos que se olvidaron de hacerlo, o el diseño ha cambiado, después de lo cual el desarrollo fue continuado por inercia por una clase.

Ahora considere el código fuente que implementa este diseño:


void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } 

Este fragmento de código es estándar para casi cualquier aplicación Flutter (se crea junto con el proyecto).


MyApp es una clase de la aplicación en sí misma, que describe los parámetros generales al crear MaterialApp: nombre de la aplicación, fuentes, colores y estilos. La pantalla principal de la aplicación también se indica aquí (para nosotros, esta es MyHomePage).


Hagamos una nota importante: en Flutter los widgets se dividen en dos tipos:


1) StatefulWidget
2) Aparato sin estado


Se requieren dos clases para describir StatefulWidget: la clase del widget en sí y la clase de su estado (en el que se realizará el trabajo principal).


StatelessWidget es descrito por una clase con un estado fijo, y solo se puede cambiar volviendo a crear desde el widget principal. Por lo tanto, para nuestros propósitos, se requiere StatefulWidget.


Ahora considere _MyHomePageState:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: <Widget>[ 

Para facilitar la percepción, una pestaña con texto está marcada en rojo, una pestaña con una imagen en verde, una pestaña de lista en azul y un menú de navegación en amarillo. Como puede ver, la interfaz se describe como un conjunto de widgets (y sus matrices) integrados entre sí:










Funciones utilizadas:
  void _onTapped(int index) { setState(() { _currentIndex = index; }); } void _setTextStyle( {double size = -1, double r = -1, double g = -1, double b = -1}) { setState(() { if (size > 0) { _size = size; } if (r > 0) { _r = r; } if (g > 0) { _g = g; } if (b > 0) { _b = b; } }); } } 

Consideremos con más detalle:


onTapped: una función que se llama al cambiar una pestaña en el menú inferior. Llama a la función setState especial, que le permite actualizar el widget actual con nuevos datos (y actualizamos la variable _currentIndex).


Veamos dónde se aplica:


 body: <Widget>[    ][_currentIndex] 

Aquí se trata de una matriz, desde donde se selecciona _currentIndex una de las opciones de diseño de pantalla, y se sustituye como una de las pestañas.


Luego viene la función _setTextStyle. Tiene un anuncio muy inusual para lenguajes tipo C.


 void _setTextStyle({double size = -1, double r = -1, double g = -1,double b = -1}) 

Los argumentos se le pasan no como una lista, sino como una matriz. Esta es una de las características muy interesantes de Dart, que le permite crear funciones con un número variable de argumentos mucho más finamente de lo que sucede en la mayoría de los otros idiomas.


Como se nombra cada argumento, podemos tomarlos en orden aleatorio. Por ejemplo:


 _setTextStyle(size: 24, b: 255) 

Dividamos la clase de pantalla grande en widgets. Es mejor desglosar por elementos lógicos, en nuestro caso, estas son pestañas. Gracias a las características de Flutter, para esto es suficiente para nosotros tomar los fragmentos de código responsables de cada pestaña y transferirlos junto con la lógica para separar las clases usando el método de compilación.


Primera pestaña:


 class TextWidget extends StatefulWidget { @override _TextWidgetState createState() => _TextWidgetState(); } class _TextWidgetState extends State<TextWidget> { double _size = 14; double _r = 0; double _g = 0; double _b = 0; @override Widget build(BuildContext context) { return Column( children: <Widget>[ Text("Example String", style: TextStyle( fontSize: _size, color: Color.fromRGBO(_r.toInt(), _g.toInt(), _b.toInt(), 1))), Container(constraints: BoxConstraints.expand(height: 32.0)), Slider( label: "${_size.toInt()} sp", value: _size, min: 10, max: 48, divisions: 38, activeColor: Colors.black, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(size: val)), Slider( label: _r.toInt().toString(), value: _r, min: 0, max: 255, divisions: 255, activeColor: Colors.red, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(r: val), ), Slider( label: _g.toInt().toString(), value: _g, min: 0, max: 255, divisions: 255, activeColor: Colors.green, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(g: val), ), Slider( label: _b.toInt().toString(), value: _b, min: 0, max: 255, divisions: 256, activeColor: Colors.blue, inactiveColor: Colors.grey, onChanged: (val) => _setTextStyle(b: val), ), ], ); } } 

Como el widget debe actualizarse (método _setTextStyle), utilizamos StatefulWidget.
No hay necesidad de actualizar las siguientes dos pestañas, por lo que usaremos StatelessWidget.


Segunda pestaña:


 class ImageWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Center(child: CircularProgressIndicator()), Center( child: FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: 'https://picsum.photos/250?image=9', ), ), ], ); } } 

Tercera pestaña:


 class ListWidget extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( itemCount: 25, itemBuilder: (BuildContext context, int index) { return Container( child: Text( 'entry $index', style: TextStyle(color: Colors.white), ), margin: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.all( Radius.circular(16.0), ), ), ); }, ); } } 

Se modificó el código de estado de la pantalla principal:


 class _MyHomePageState extends State<MyHomePage> { int _currentIndex = 0; Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), actions: <Widget>[ IconButton(icon: Icon(Icons.navigate_next), onPressed: next) ], ), body: <Widget>[ TextWidget(), ImageWidget(), ListWidget(), ][_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: _onTapped, items: [ BottomNavigationBarItem( icon: new Icon(Icons.text_format), title: new Text('Text'), ), BottomNavigationBarItem( icon: new Icon(Icons.image), title: new Text('Image'), ), BottomNavigationBarItem( icon: Icon(Icons.list), title: Text('ListView'), ) ], )); } 

Entonces, dividimos fácilmente una pantalla grande en una pantalla pequeña y tres widgets pequeños. Puede notar que en las pantallas de Flutter no hay diferencias conceptuales con respecto a los widgets (más precisamente, los widgets asumen las funciones de actividad, fragmento y vistas personalizadas). Esta característica es muy conveniente cuando la aplicación necesita una vista de pantalla completa de cualquier elemento, para esto puede usar nuestros widgets con un mínimo de refinamiento.


Y, sin embargo, existen diferencias mínimas entre un widget que se usa como pantalla y un widget normal. El elemento raíz del widget de pantalla debe ser un objeto Scaffold (le permite agregar appBar, bottomNavigationBar, floatingActionButton, drawer, etc.).


Los widgets normales no tienen esta limitación, ya que al usar el método de compilación se incrustarán en la pantalla principal, donde Scaffold ya está disponible.


Afortunadamente, agregar Scaffold a un widget regular no afecta su rendimiento.


También puede agregar SafeArea (para proporcionar una sangría para la barra de estado). Se obtiene la siguiente conversión simple:


De:


 @override Widget build(BuildContext context) { return []; } 

Para:


 @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: [] ), ); } 

Bueno, ahora volviendo a la discusión de los pros y los contras de Flutter.


Flutter ha sido lanzado recientemente, por lo que los errores son bastante comunes. Esto es especialmente notable al actualizar Flutter: algunas bibliotecas comienzan a funcionar con errores.


- Inestabilidad (recientemente dejó beta)


Obviamente, cuando usa el nuevo marco, tiene muchas menos bibliotecas a su disposición que con el desarrollo nativo de Android / iOS. Sin embargo, todavía hay muchas bibliotecas para Flutter, y continúan apareciendo con gran velocidad. Por ejemplo, muchas bibliotecas se agregaron en la segunda mitad de 2018, aparentemente, en preparación para la primera versión estable, y las bibliotecas más importantes (Google Analytics, Firebase, Maps, etc.) existían antes de eso.


- Menos bibliotecas que para el desarrollo nativo
+ Las bibliotecas más importantes ya están allí, constantemente salen nuevas.


¡Es hora de hacer balance! Recordemos todos los pros y los contras, organizando los elementos desde las ventajas más significativas hasta las desventajas más significativas:


+ Multiplataforma
+ Perspectiva y desarrollo activo
+ Las bibliotecas más importantes ya están allí, constantemente salen nuevas.
+ Motor gráfico propio
+ La interfaz se divide fácilmente en módulos separados


- El paquete de instalación final es más grande, ya que se le agrega la máquina virtual Dart
- La interfaz se crea usando código, lo que hace que la línea entre la lógica y el diseño sea mucho más delgada
- Menos bibliotecas (e información) que para el desarrollo nativo
- Inestabilidad (recientemente dejó beta)


Gracias por su atencion!

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


All Articles