基于Flutter构建小型新闻App

目录

1. 概述

1.1 功能概述

1.2 技术准备

1.3 源码地址

2. App首页

2.1 pubspec依赖

2.2 热门首页组件

2.2.1 DefaultTabController

2.2.2 Swiper

2.3 新闻API数据访问 

2.4 热门首页效果图

3. 新闻分类

3.1 GestureDetector

3.2 新闻分类效果图

4. 收藏功能

4.1 fluttertoast

4.2 shared_preferences

4.3 收藏效果图

5. 相关文档和总结


最近在研究基于Flutter构建一个简单的新闻资讯app,主要参考:用Flutter极速构建原生应用(需要电子书的话可以私聊),但是这本书有部分代码引用的组件版本已经不适用所以做了一些调整。以下是对于开发过程和遇到的一些问题的总结。

1. 概述

1.1 功能概述

对于Flutter的环境配置就不做总结了,为了节省时间大家可以用IntelliJ IDEA专业版,里面就可以创建Flutter项目。主要包含三个部分:

  • 热门新闻列表。
  • 分类新闻列表。
  • 新闻详情页。
  • 收藏功能。

1.2 技术准备

应用的首页用来展示热门新闻,我们可以选取天行数据的“综合新闻”接口服务,接口服务详细信息地址:综合新闻API接口 - 天行数据TianAPI。

在这注册一个账号用来做app测试。

然后创建一个Flutter应用,目录架构如下:

1.3 源码地址

项目源码:基于Flutter构建的新闻App。

Git地址:GitHub - BAStriver/flutter_test: test。

2. App首页

这里主要引用到DefaultTabController组件和Swiper组件。

  • 使用DefaultTabController组件来实现多模块的聚合页面。
  • 使用Swiper实现首页图片轮播。

首先在category和home文件夹下新建两个Dart文件,命名为category_view.dart与home_view.dart。目前实现如下效果:

2.1 pubspec依赖

如下是这个app的主要依赖设置:

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  http: ^1.1.2
  fluttertoast: ^8.2.4
  shared_preferences: ^2.2.2

2.2 热门首页组件

2.2.1 DefaultTabController

Widget _containerView(BuildContext context) {
    return Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: DefaultTabController(
          length: 2,
          child: Scaffold(
            appBar: AppBar(
              bottom: const TabBar(
                tabs: [
                  Tab(
                    child: Text(
                      "popular",
                      style: TextStyle(color: Colors.black),
                    ),
                  ),
                  Tab(
                    child: Text(
                      "classifications",
                      style: TextStyle(color: Colors.black),
                    ),
                  )
                ],
                indicatorColor: Colors.green,
              ),
              title: const Text(
                "ALl News",
                style: TextStyle(color: Colors.black),
                textAlign: TextAlign.center,
              ),
              backgroundColor: Colors.white,
              actions: <Widget>[
                GestureDetector(
                  child: Container(
                    width: 60,
                    child: const Icon(Icons.collections),
                  ),
                  onTap: () {
                    print('enter collection view.');
                    Navigator.push(context, MaterialPageRoute(builder: (context) {
                      print('enter collection view2.');
                      return CollectionView();
                    }));
                  },
                )
              ],
            ),
            body: TabBarView(
              children: [HomeView(), CategoryView()],
            ),
          )),
    );
  }

2.2.2 Swiper

Widget _buildSwiper(BuildContext context) {
    return Container(
      height: 150,
      child: Swiper(
        pagination: const SwiperPagination(),
        control: const SwiperControl(),
        autoplay: true,
        itemCount: 3,
        itemBuilder: (BuildContext context, int index) {
          return Container(
            margin: const EdgeInsets.only(bottom: 5),
            color: Colors.orange,
            width: MediaQuery.of(context).size.width,
            height: 150,
            child: Image.network(
              _dataList[_dataList.length - 1].picUrl,
              height: 150,
              width: MediaQuery.of(context).size.width,
              fit: BoxFit.fitWidth,
            ),
          );
        },
      ),
    );
  }

这里如果参考书上的写法会有问题,所以为了解决升级到Dart3.0后Swiper不兼容的问题可以参考:由于flutter_app依赖于flutter_swiper>=0.0.2,不支持零安全,版本解决失败。_because book depends on flutter_swiper >=0.0.2 whi-CSDN博客

2.3 新闻API数据访问 

Future<HomeModel> queryHomeData(int page) async {
    var url = Uri.parse('https://apis.tianapi.com/generalnews/index');

    var headers = <String, String>{"Access-Control-Allow-Origin": "*","Content-Type":"application/x-www-form-urlencoded"};
    var body = <String, String>{"key": URL_KEY, "num": "10", "page": "$page"};

    final response = await http.post(url,body: body, headers: headers);
    Map<String, dynamic> jsonMap = json.decode(response.body);
    return HomeModel.fromJson(jsonMap);
  }

这里会涉及到数据模型的构建和加载,可以参考:A value of type 'X' can't be assigned to a variable of type 'List' - 糯米PHP

2.4 热门首页效果图

3. 新闻分类

这里主要引用到GestureDetector组件。

关于新闻分类主页采用网格布局,根据天行数据网上提供的新闻接口定义10个分类。

final List<String> _categorys = [
    "GeneralNews",
    "CarNews",
    "DomesticNews",
     "AnimeNews",
    "FinancialNews",
    "GameNews",
    "InternationalNews",
    "AINews",
    "MilitaryNews",
    "SportNews"
  ];

3.1 GestureDetector

点击一个分类,页面会跳转到分类列表页。

关于详细的组件回调事件可以参考:

Flutter--GestureDetector手势识别组件_flutter gesturedetector-CSDN博客

Widget _getItem(BuildContext context, int index) {
    return Container(
      width: MediaQuery.of(context).size.width,
      height: 130,
      child: Row(
        children: <Widget>[
          GestureDetector(
            child: Container(
              width: MediaQuery.of(context).size.width / 2,
              color: index % 2 == 0 ? Colors.orange : Colors.blueAccent,
              height: 130,
              child: Center(
                child: Text(
                  _categorys[index * 2],
                  textAlign: TextAlign.center,
                  style: const TextStyle(fontSize: 30, color: Colors.white),
                ),
              ),
            ),
            onTap: () {
              Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
                return CategoryListView(CATEGORY_KEYS[_categorys[index * 2]]!, _categorys[index * 2]);
              }));
            },
          ),
          GestureDetector(
            child: Container(
              width: MediaQuery.of(context).size.width / 2,
              color: index % 2 == 0 ? Colors.blueAccent : Colors.orange,
              height: 130,
              child: Center(
                child: Text(
                  _categorys[index * 2 +1],
                  textAlign: TextAlign.center,
                  style: const TextStyle(fontSize: 30, color: Colors.white),
                ),
              ),
            ),
            onTap: () {
              Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
                return CategoryListView(CATEGORY_KEYS[_categorys[index * 2 + 1]]!, _categorys[index * 2 + 1]);
              }));
            },
          )
        ],
      ),
    );
  }

3.2 新闻分类效果图

进入一般新闻的分类页面:

4. 收藏功能

这里主要引用了fluttertoast和shared_preferences组件。

  • fluttertoast实现弹窗效果。
  • shared_preferences实现本地缓存。

4.1 fluttertoast

实现弹窗是否收藏新闻。

Widget _buildItem(BuildContext context, int index) {
    return Container(
      height: 110,
      width: MediaQuery.of(context).size.width,
      margin: const EdgeInsets.only(bottom: 1),
      color: Colors.amber,
      child: GestureDetector(
        child: Row(
          children: <Widget>[
            Container(
              color: Colors.grey,
              child: Image.network(
                // "http://n.sinaimg.cn/sinakd202124s/162/w550h412/20210204/6706-kirmait9301473.jpg",
                _dataList[index].picUrl,
                width: 130,
                height: 110,
                fit: BoxFit.fitHeight,
              ),
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Container(
                  margin: const EdgeInsets.only(left: 10, top: 10, right: 10),
                  width: MediaQuery.of(context).size.width - 130 - 20,
                  child: Text(
                    _dataList[index].title,
                    overflow: TextOverflow.ellipsis,
                    maxLines: 2,
                    style: const TextStyle(
                        fontSize: 15, fontWeight: FontWeight.bold),
                  ),
                ),
                Container(
                  margin: const EdgeInsets.only(left: 10, top: 5),
                  child: Text(_dataList[index].description),
                ),
                Container(
                  margin: const EdgeInsets.only(left: 10, top: 5),
                  child: Text(_dataList[index].ctime),
                ),
              ],
            )
          ],
        ),
        onLongPress: () {
          showDialog(
              context: context,
              builder: (BuildContext context) {
                return AlertDialog(
                  title: Text('Do you want to save it ?'),
                  actions: <Widget>[
                    TextButton(
                        onPressed: () {
                          _addCollection(
                              _dataList[index].id, _dataList[index].title);
                          Navigator.of(context).pop();
                        },
                        child: Text('Yes')),
                    TextButton(
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                        child: Text('No')),
                  ],
                );
              });
        },
      ),
    );
  }

4.2 shared_preferences

实现本地缓存。

void _addCollection(String id, String title) async {
    print('id: ' + id);
    print('title: ' + title);
    SharedPreferences? preferences = await SharedPreferences.getInstance();
    String? data = preferences.getString(id);
    if (data == null) {
      await preferences.setString(id, title);
      Fluttertoast.showToast(msg: 'saved successfully.');
    } else {
      Fluttertoast.showToast(msg: 'the new already existing.');
    }
  }

4.3 收藏效果图

长按新闻。

收藏成功。

 

点击主页右上角的收藏图标进入收藏页面:

5. 相关文档和总结

开发体验初探 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter

如何搭建flutter开发环境_flutter环境搭建-CSDN博客

Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用

注:

1.遇到跨域问题访问不到图片可以参考:

开发环境如需解决跨域问题

flutter for web 带cookie的网络请求跨域问题处理

2.关于GestureDetector组件的用法可以参考:Flutter--GestureDetector手势识别组件

3.关于SharedPreferences组件的用法可以参考:Flutter 数据存储--shared_preferences使用详情

4.遇到:MissingPluginException (MissingPluginException(No implementation found for method... 需要重新启动项目。

5.遇到Navigator无法正常跳转页面时候可以参考:

Flutter无法跳转页面的解决方法(push方法无效) - 简书

Navigator的正确打开方式-CSDN博客

比如第4节开发收藏功能的时候遇到这个无法跳转的问题,main.dart做了如下的修改:

6.Flutter有两个App主题风格可以引用,包括:cupertino(IOS)、material(Android),具体的官方文档可以参考:Cupertino (iOS-style) widgets | Flutter 、Material Components widgets | Flutter。

关于这些风格的Widgets用法也可以参考:开启Fluter基础之旅<三>-------Material Design风格组件、Cupertino风格组件、Flutter页面布局篇...-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/285304.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

详解 MySql InnoDB 的 MVCC 实现机制

目录 一. 前言 二. 认识 MVCC 2.1. 什么是 MVCC&#xff1f; 2.2. 什么是当前读和快照读&#xff1f; 2.3. 当前读、快照读和 MVCC 的关系 2.4. MVCC 能解决什么问题&#xff0c;好处是什么&#xff1f; 2.5. 小结 三. MVCC 的实现原理 3.1. 隐式字段 3.2. undo 日志…

SQL常见面试题

今天刷了一遍牛客里的必知必会题&#xff0c;一共50道题&#xff0c;大部分都比较基础&#xff0c;下面汇总一下易错题。 SQL81 顾客登录名 本题几个关键点&#xff1a; 登录名是其名称和所在城市的组合&#xff0c;因此需要使用substring()和concat()截取和拼接字段。得到登…

SpringBoot解决前后端分离跨域问题:状态码403拒绝访问

最近在写和同学一起做一个前后端分离的项目&#xff0c;今日开始对接口准备进行 登录注册 的时候发现前端在发起请求后&#xff0c;抓包发现后端返回了一个403的错误&#xff0c;解决了很久发现是【跨域问题】&#xff0c;第一次遇到&#xff0c;便作此记录✍ 异常描述 在后端…

前端:html+css+js实现CSDN首页

提前说一下&#xff0c;只实现了部分片段哈&#xff01;如下&#xff1a; 前端&#xff1a;htmlcssjs实现CSDN首页 1. 实现效果2. 需要了解的前端知识3. 固定定位的使用4. js 监听的使用4. 参考代码和运行结果 1. 实现效果 我的实现效果为&#xff1a; 原界面如下,网址为&…

计算机网络(1)

计算机网络&#xff08;1&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 计算机网络和因特网&#xff08;1&#xff09;因特网概念解读服务常见的服务 协议网络边缘特点强调 网络核心特点强调 小程一言 我的计算机网络专栏&#xff0c;是自己在计算机网络…

1. Spring概述

概述 Spring 是一个开源框架Spring 为简化企业级开发而生&#xff0c;使用 Spring&#xff0c;JavaBean 就可以实现很多以前要靠 EJB 才能实现的功能。同样的功能&#xff0c;在 EJB 中要通过繁琐的配置和复杂的代码才能够实现&#xff0c;而在 Spring 中却非常的优雅和简洁。…

软件运维实施维保方案

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 项目开发、管理、实施、运维、结项、验收等全文档获取&#xff1a;软件开发全套资料-CSDN博客

【LeetCode每日一题】1599. 经营摩天轮的最大利润(模拟)—2024新年快乐!

2024-1-1 文章目录 [1599. 经营摩天轮的最大利润](https://leetcode.cn/problems/maximum-profit-of-operating-a-centennial-wheel/)思路&#xff1a; 1599. 经营摩天轮的最大利润 思路&#xff1a; 1.对摩天轮的运转情况进行模拟&#xff0c; 2.遍历数组&#xff0c;分别计…

简单FTP客户端软件开发——JavaFX开发FTP客户端

文章目录 导入外部包commons-net-3.10.0.jarJavaFX开发客户端 FTP客户端要求如下&#xff1a; 简单FTP客户端软件开发 网络环境中的一项基本应用就是将文件从一台计算机中复制到另一台可能相距很远的计算机中。而文件传送协议FTP是因特网上使用得最广泛的文件传送协议。FTP使用…

Golang leetcode707 设计链表 (链表大成)

文章目录 设计链表 Leetcode707不使用头节点使用头节点 推荐** 设计链表 Leetcode707 题目要求我们通过实现几个方法来完成对链表的各个操作 由于在go语言中都为值传递&#xff0c;&#xff08;注意这里与值类型、引用类型的而区别&#xff09;&#xff0c;所以即使我们直接在…

RocketMQ 生产者源码分析:DefaultMQProducer、DefaultMQProducerImpl

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

【面试】面向对象编程的三大概念(实例辅助记忆)

【面试】面向对象编程的三大概念&#xff08;实例辅助记忆&#xff09; 虑面向对象编程的三大特性&#xff0c;它们是&#xff1a; 封装&#xff08;Encapsulation&#xff09;&#xff1a; 将对象的状态和行为封装在一起&#xff0c;对外部隐藏对象的内部实现细节。这样可以防…

Nginx 简介和入门 - part1

虽然作为1个后端程序员&#xff0c; 终究避不开这东西 安装Nginx 本人的测试服务器是debian &#xff0c; 安装过程跟ubuntu基本一样 sudo apt-get install nginx问题是 nginx 安装后 执行文件在/usr/sbin 而不是/usr/bin 所以正常下普通用户是无法使用的。 必须切换到root…

事件循环的理解

1.单线程 Js是一个单线程的语言,代码只能一行一行去执行,遇到同步的代码就直接执行了,如果遇到异步的代码怎么办&#xff1f; 不可能等到异步的代码执行完&#xff0c;在去执行后面同步的代码。 2.主线程 遇到同步的代码,就在主线程里面直接执行了。 3.任务队列 遇到异步的…

数位dp详解,记忆化搜索,递推,OJ精讲

文章目录 前言引例-不降数前置知识差分转换枚举技巧前缀状态 状态分析状态设计状态转移初始状态记忆化搜索 引例代码实现状态初始化数位初始化记忆化搜索 非递归如何实现&#xff1f;状态设计状态转移算法原理算法实现初始化递推求解 OJ精讲Good Numbers不要62不含连续1的非负整…

redis 从0到1完整学习 (十四):RedisObject 之 ZSet 类型

文章目录 1. 引言2. redis 源码下载3. redisObject 管理 ZSet 类型的数据结构4. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff1a;安装&初识 redis》 《redis 从0到1完整学习 &#xff08;二&#xff09;&#xff1a;re…

【基础】【Python网络爬虫】【1.认识爬虫】什么是爬虫,爬虫分类,爬虫可以做什么

Python网络爬虫基础 认识爬虫1.什么是爬虫2.爬虫可以做什么3.为什么用 Ptyhon 爬虫4.爬虫的分类通用爬虫聚焦爬虫功能爬虫增量式爬虫分布式爬虫 5.爬虫的矛与盾&#xff08;重点&#xff09;6.盗亦有道的君子协议robots7.爬虫合法性探究 认识爬虫 1.什么是爬虫 网络爬虫&…

LAYABOX:2024新年寄语

2024新年寄语 过去的一年&#xff0c;尽管许多行业面临严峻挑战和发展压力&#xff0c;小游戏领域却逆势上扬&#xff0c;年产值首次突破400亿元大关&#xff0c;众多优质小游戏企业收获颇丰。 对此&#xff0c;祝福大家&#xff0c;2024一定更好&#xff01; 过去的一年&#…

基于低代码的指尖遐想_2

广义低代码解决了企业或个人的哪些问题&#xff0c;其快速发展的背后说明了什么&#xff1f; 基于一个简要的企业信息化系统来分析阐述&#xff08;天下大事合久必分&#xff0c;分久必合&#xff09;&#xff1a; 2010年前后&#xff0c;一个合格的程序员&#xff0c;可以做需…

YOLOv8改进 | 2023主干篇 | FasterNeT跑起来的主干网络( 提高FPS和检测效率)

一、本文介绍 本文给大家带来的改进机制是FasterNet网络&#xff0c;将其用来替换我们的特征提取网络&#xff0c;其旨在提高计算速度而不牺牲准确性&#xff0c;特别是在视觉任务中。它通过一种称为部分卷积&#xff08;PConv&#xff09;的新技术来减少冗余计算和内存访问。…