热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter简易新闻项目

目标使用flutter快速开发Android和iOS的简易的新闻用户端API使用的是showapi(易源数据)加载热门微信文章效果比照AndroidiOSimageimageima
目标

使用flutter快速开发 Android 和 iOS 的简易的新闻用户端
API使用的是 showapi(易源数据) 加载热门微信文章

效果比照
AndroidiOS
imageimage
imageimage
imageimage
简介

这是一个建议的新闻用户端 页面非常简单

通过网络请求加载 分类数据 和 分类介绍数据 (key都在代码里了,轻量使用~)

UI上几乎是没有任何特点

使用BottomNavigationBar 分成3个控制器

首页使用DefaultTabController管理内容

相关依赖:

http: "^0.11.3" #网络请求cached_network_image: "^0.4.1" #图片加载cupertino_icons: ^0.1.2 #iconflutter_webview_plugin: ^0.1.6 #webviewshared_preferences: ^0.4.2 #持久化数据url_launcher: ^3.0.3 #调用系统浏览器代码

使用单例来保存数据

因为分类准则上是没有变化的,我这里就使用单例来保存从API请求的分类数据,减少请求次数(API请求次数有限)

class UserSinglen { List allTypes = []; static final UserSinglen _singleton = new UserSinglen._internal(); factory UserSinglen() { return _singleton; } UserSinglen._internal();}

使用Shared保存数据

保存当前选中的分类

class Shared { //保存分类 static Future saveSelectedType(List list) async { SharedPreferences pre = await SharedPreferences.getInstance(); await pre.setStringList("selectedTypeIds",list); print(list); return; } //获取已选择的分类 static Future> getSelectedType() async { SharedPreferences pre = await SharedPreferences.getInstance(); try { List typeIds = pre.getStringList("selectedTypeIds"); print("typeids = $typeIds"); return typeIds; } catch (e) { return null; } }}

BottomNavigationBar的使用

构建NavigationIcon

为底部的icon封装,方便找到对应的控制器

class NavigationIcon { NavigationIcon({ Widget icon, Widget title, TickerProvider vsync, }) : item = new BottomNavigationBarItem( icon: icon, title: title, ), cOntroller= new AnimationController( duration: kThemeAnimationDuration, vsync: vsync, ); final BottomNavigationBarItem item; final AnimationController controller;}

构建当前控制器

当前控制器是Stateful类型,刷新页面
初始化3个控制器

class Index extends StatefulWidget { const Index({ Key key }) : super(key: key); @override State createState() => new IndexState();}class IndexState extends State with TickerProviderStateMixin { List navigationIcons; List pageList; int currentPageIndex = 0; StatefulWidget currentWidget; @override void initState() { // TODO: implement initState super.initState(); navigatiOnIcons= [ new NavigationIcon( icon: new Icon(Icons.home), title: new Text("首页"), vsync: this, ), new NavigationIcon( icon: new Icon(Icons.category), title: new Text("分类"), vsync: this, ), new NavigationIcon( icon: new Icon(Icons.info), title: new Text("关于"), vsync: this, ) ]; pageList = [ new Home(key: new Key("home"),), new Category(key: new Key("category"),), new About(), ]; for(NavigationIcon view in navigationIcons) { view.controller.addListener(rebuild()); } currentWidget = pageList[currentPageIndex]; } @override void dispose() { // TODO: implement dispose super.dispose(); for (NavigationIcon view in navigationIcons) { view.controller.dispose(); } }rebuild(){ print("rebuild"); setState(() {});} @override Widget build(BuildContext context) { final BottomNavigationBar bottomNavigatiOnBar= new BottomNavigationBar( items: navigationIcons.map(((i) => i.item)).toList(), currentIndex: currentPageIndex, fixedColor: Config.mainColor, type: BottomNavigationBarType.fixed, onTap: (i) { setState(() { navigationIcons[i].controller.reverse(); currentPageIndex = i; navigationIcons[i].controller.forward(); currentWidget = pageList[i]; }); }, ); return new MaterialApp( theme: Config.themeData, home: new Scaffold( body: Center( child: currentWidget, ), bottomNavigationBar: bottomNavigationBar, ), ); }}

首页

首页实时获取存储在本地的已选择分类,与单例中的所有分类做比照,获取对应的类型id
(shared_preferences只能存储基本数据类型)

class Home extends StatefulWidget { const Home({Key key}) : super(key: key); @override State createState() { // TODO: implement createState return new HomeState(); }}class HomeState extends State { bool _isloading = true; List _list; @override void initState() { // TODO: implement initState super.initState(); API.featchTypeListData((List callback) { Shared.getSelectedType().then((onValue) { print(onValue); if (onValue != null) { print("lentch = "); print(onValue.length); setState(() { _isloading = false; _list = callback.where((t) => onValue.contains(t.id)).toList(); }); } }); }, errorback: (error) { print("error:$error"); }); } @override Widget build(BuildContext context) { // TODO: implement build return _isloading ? new Scaffold( appBar: new AppBar( title: new Text("loading..."), ), body: new Center( child: new CircularProgressIndicator( backgroundColor: Colors.black, ), ), ) : new DefaultTabController( length: _list.length, child: new Scaffold( appBar: new AppBar( title: new Text("新闻"), bottom: new TabBar( isScrollable: true, labelColor: Colors.white, unselectedLabelColor: Colors.black, tabs: _list.map((f) => new Tab(text: f.name)).toList()), ), body: new TabBarView( children: _list.map((f) => new Content(channelId: f.id)).toList(), )), ); } @override void dispose() { // TODO: implement dispose super.dispose(); }}

分类

这个页面也很简单,将已选择的分类id存进shared_preferences中就行

class Category extends StatefulWidget { const Category({Key key}) : super(key: key); @override State createState() => new CategoryState();}class CategoryState extends State { List _list = []; bool _isloading = true; @override void initState() { // TODO: implement initState super.initState(); API.featchTypeListData((List callback) { Shared.getSelectedType().then((onValue) { setState(() { _isloading = false; _list = callback .map((f) => new WeType(f.id, f.name, onValue.contains(f.id))) .toList(); }); }); }, errorback: (error) { print("error:$error"); }); } _onTapButton(WeType type) { setState(() { _list = _list.map((WeType f) { if (f.id == type.id) { f.isSelected = !f.isSelected; } return f; }).toList(); Shared.saveSelectedType( _list.where((t) => t.isSelected).map((f) => f.id).toList()); }); } _selectAll() { print("all"); var r = _list.where((t) => t.isSelected).toList(); bool res = r.length <_list.length ? true : false; setState(() { _list = _list.map((f) => new WeType(f.id, f.name, res)).toList(); Shared.saveSelectedType( _list.where((t) => t.isSelected).map((f) => f.id).toList()); }); } @override Widget build(BuildContext context) { return _isloading ? CircularProgressIndicator() : new Scaffold( appBar: new AppBar( title: new Text("分类"), actions: [ new FlatButton( onPressed: _selectAll, child: new Center( child: new Text( "全选", style: new TextStyle(color: Colors.white), )), ) ], ), body: new GridView.count( // Create a grid with 2 columns. If you change the scrollDirection to // horizontal, this would produce 2 rows. crossAxisCount: 3, crossAxisSpacing: 0.0, childAspectRatio: 2.0, // Generate 100 Widgets that display their index in the List children: _list .map((f) => new FlatButton( padding: const EdgeInsets.all(10.0), onPressed: () { _onTapButton(f); }, child: new Center(child: _Button(f.name, f.isSelected)), )) .toList(), )); }}class _Button extends StatelessWidget { final String title; final bool isSelected; _Button(this.title, this.isSelected); @override Widget build(BuildContext context) { // TODO: implement build return new Stack( alignment: AlignmentDirectional.center, children: [ new Container( child: new Center( child: new Text(title), ), decoration: new BoxDecoration( color: isSelected ? Colors.blue[200] : Colors.white, borderRadius: new BorderRadius.all( const Radius.circular(20.0), ), border: new Border.all( color: isSelected ? Colors.white : Colors.blue[100],//边框颜色 width: 1.0,//边框宽度 ), ), ), new Container( child: new Center( child: isSelected ? new Icon( Icons.check, color: Colors.white, ) : null, ), ), ], ); }}代码地址

Flutter-news
欢迎点赞


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何在 Android 中通过代码模拟用户的点击和滑动操作,包括参数说明、事件生成及处理逻辑。详细解析了视图(View)对象、坐标偏移量以及不同类型的滑动方式。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了如何在BackTrack 5中配置和启动SSH服务,确保其正常运行,并通过Windows系统成功连接。涵盖了必要的密钥生成步骤及常见问题解决方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 使用 NDB 提升 Node.js 应用调试体验
    本文介绍了由 Google Chrome 实验室推出的新一代 Node.js 调试工具 NDB,旨在为开发者提供更加高效和便捷的调试解决方案。 ... [详细]
  • Flutter 高德地图插件使用指南
    本文档详细介绍了如何在Flutter项目中集成和使用高德地图插件,包括安装、配置及基本使用方法。 ... [详细]
  • Windows 系统中 Flutter 与 IntelliJ IDEA 的环境配置指南
    本指南详细介绍了如何在 Windows 操作系统上设置 Flutter 开发环境,并集成至 IntelliJ IDEA 中,适合初学者及专业人士参考。 ... [详细]
author-avatar
最爱一片小舟
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有