Bienvenido, soy Luis y para hoy les traigo este tutorial.
Índice
Cotizaciones de acciones multiplataforma
En la primera pieza de esta serie, cubrimos cómo mostrar acciones en su aplicación Flutter. Creamos una API JSON, Node y Express integrados, que devolvieron acciones ficticias a la aplicación Flutter.
En esta pieza, completaremos la aplicación de acciones mostrando noticias en una vista de noticias personalizada. El usuario también podrá utilizar gestos para realizar operaciones de deslizamiento hacia arriba y hacia abajo en la vista de noticias.
Actualizar el servidor
Comenzaremos agregando un nuevo endpoint a nuestro servidor , que se encargará de brindar noticias JSON falsas al usuario. La implementación se muestra a continuación:
app.get("/top-news", (req, res) => { let articles = [ { title: "The Bull Market is Charging into 2020", publication: "THE WALSTREET JOURNAL", imageURL: "https://i.ytimg.com/vi/gtkiRJwSN10/maxresdefault.jpg" }, { title: "Tencent Groups 10% of Univercal Music", publication: "Bloomberg", imageURL: "https://prod.static9.net.au/_/media/2019/09/02/10/36/nine_news_melbourne_1600x900_fullstory_nightly6pm.jpg" } ]; res.json(articles); });
Al igual que con el punto final de stock, simplemente devolvemos una lista de artículos como una respuesta JSON codificada. Si se siente aventurero, puede consultar el servicio NewsAPI.org , que se puede utilizar para devolver noticias reales en vivo.
Obteniendo noticias destacadas usando Flutter
El siguiente paso es obtener las noticias de la API JSON. Esta es la responsabilidad de nuestro cliente HTTP, representado por la clase Webservice
. La implementación de la función getTopNews
se muestra a continuación:
Future<List<NewsArticle>> getTopNews() async { final url = "https://silicon-rhinoceros.glitch.me/top-news"; final response = await http.get(url); if(response.statusCode == 200) { Iterable json = jsonDecode(response.body); return json.map((newsArticle) => NewsArticle.fromJson(newsArticle)).toList(); } else { throw Exception("Error fetching news"); } }
La función getTopNews
es similar a getStocks
, que simplemente usa la URL para obtener los datos. Posteriormente, los datos se completan en el modelo NewsArticle
. La implementación del modelo NewsArticle
se muestra a continuación:
class NewsArticle { final String title; final String publication; final String imageURL; NewsArticle({this.title, this.publication, this.imageURL}); factory NewsArticle.fromJson(Map<String, dynamic> json) { return NewsArticle( title: json["title"], publication: json["publication"], imageURL: json["imageURL"] ); } }
El modelo NewsArticle
consta de tres propiedades: título, publicación e imageURL. La función fromJson
sirve como método de fábrica y crea una nueva instancia NewsArticle
basada en el objeto json. Ahora que nuestro modelo y servicio web están listos, podemos concentrarnos en implementar los modelos de vista.
Implementación de NewsArticleViewModel
El NewsArticleViewModel
es responsable de proporcionar datos de noticias a la vista. La implementación de NewsArticleViewModel
se muestra a continuación:
class NewsArticleViewModel { final NewsArticle newsArticle; NewsArticleViewModel({this.newsArticle}); String get title { return newsArticle.title; } String get publication { return newsArticle.publication; } String get imageURL { return newsArticle.imageURL; } }
NewsArticleViewModel
toma en el modelo NewsArticle
como un argumento y expone varias propiedades a los datos de acceso asociados con title
, publication
y imageURL
.
Ahora, podemos actualizar nuestro StockListViewModel
para agregar una nueva función load
. Este será responsable de obtener las acciones y las noticias de nuestra API personalizada. La función load
se implementa a continuación:
Future<void> load() async { final list = await Future.wait([Webservice().getStocks(), Webservice().getTopNews()]); stocks = list.first.map((stock) => StockViewModel(stock: stock)).toList(); // stocks newsArticles = list.last.map((newsArticle) => NewsArticleViewModel(newsArticle: newsArticle)).toList(); // news articles notifyListeners(); }
Dentro de la función de carga, usamos Future.wait
para esperar a que se completen ambos futuros. Una vez que se completan los futuros, devuelve una lista de valores asociados con los futuros. Accedemos a los valores usando la primera y última función auxiliar en la matriz y finalmente llamamos notifyListeners()
.
Visualización de las noticias principales
El siguiente paso es mostrar los principales artículos de noticias en la vista. Hemos implementado un widget NewsList
, que se encargará de rellenar las novedades en pantalla. los widget NewsList
requiere tres argumentos:
articles
– Representa los artículos de noticias para mostrar en pantalla.onHeaderTap
– Función de devolución de llamada para disparar cuando el usuario toca el encabezadoonDragUpdate
– Función de devolución de llamada para disparar cuando el usuario arrastra la vista
En lugar de manejar eventos dentro del NewsList
vista, le estamos dando la oportunidad a los padres. Esto significa que el padre es responsable de pasar los artículos e implementar la onHeaderTap
y onDragUpdate
eventos.
Aquí está la implementación completa del widget NewsList
:
import 'package:flutter/material.dart'; import 'package:stocks_app_flutter/view_models/home_page_view_model.dart'; class NewsList extends StatelessWidget { final List<NewsArticleViewModel> articles; final Function onHeaderTapped; final Function(DragUpdateDetails) onDragUpdate; NewsList({this.articles, this.onHeaderTapped, this.onDragUpdate}); @override Widget build(BuildContext context) { return GestureDetector( onTap: onHeaderTapped, onVerticalDragUpdate: onDragUpdate, child: SafeArea( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: Colors.grey[850]), padding: EdgeInsets.all(20), height: 800, width: MediaQuery.of(context).size.width, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text("Top Stories", style: TextStyle( color: Colors.white, fontSize: 34, fontWeight: FontWeight.bold)), Text("From News", style: TextStyle( color: Colors.grey, fontSize: 22, fontWeight: FontWeight.bold)), Divider(color: Colors.grey[400]), Expanded( child: ListView.builder( itemCount: articles.length, itemBuilder: (context, index) { return ListTile( contentPadding: EdgeInsets.only(left: 0), title: Wrap(children: <Widget>[ Text(articles[index].publication, style: TextStyle(color: Colors.white, fontSize: 24)), Text(articles[index].title, style: TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold)) ]), trailing: Image.network(articles[index].imageURL), ); }, ), ) ])), ), ); } }
La mayor parte del código se utiliza para configurar la interfaz de usuario para NewsList
. También usamos GestureDetector
para manejar eventos táctiles. los onTap
y onVerticalDragUpdate
los eventos se asignan al onHeaderTapped
y onDragUpdate
cierres, lo que significa que serán manejados por los padres.
En la vista de los padres, usamos el AnimatedContainer
para animar nuestros movimientos de arrastre.
Positioned( bottom: 0, child: AnimatedContainer( height: _expanded ? 800 : 210, duration: Duration(milliseconds: 500), curve: Curves.easeInOut, child: NewsList( articles: vm.newsArticles, onHeaderTapped: () { setState(() { _expanded = !_expanded; }); }, onDragUpdate: (details) { if(details.primaryDelta < 0) { setState(() { _expanded = true; }); } else { setState(() { _expanded = false; }); } }), ), ) ]));
Según la dirección del arrastre, expandimos y compactamos la vista NewsList
. La animación se muestra a continuación:
En esta serie de dos partes, aprendiste cómo crear una aplicación de acciones de Apple en Flutter. También usamos MVVM
y el Provider
patrón para construir nuestra aplicación Flutter, lo que resultó en una base de código más estructurada y mantenible. GitHub.
Recursos
Gracias por leer.
[…] Cree la aplicación Apple Stocks usando Flutter Parte 2 […]