【Flutter】新闻小项目

使用天行数据网提供的新闻接口实现一个新闻推送小项目

前言

天行数据网虽然不是免费提供数据接口调用服务,但对于新注册的用户,会提供10000次的免费接口调用额度,对于具体申请的某类接口提供了100次的免费调用额度。所以要使用天行数据网提供的接口服务,首先要注册成为天行数据网的用户,然后申请某种数据接口服务。


一、注册天行网申请接口?

链接: link.点击进入天行网官网注册,并找到自己感兴趣的接口,申请即可。本文选用接口如下。
在这里插入图片描述

二、在flutter中使用http请求插件,并获取json,转化为LIST

1.引入库

在这里插入图片描述在这里插入图片描述
代码如下(示例):
Flutter中使用http请求获取json使用异步方法
代码如下

 Future<List<CommonModel>> getDatas() async {
    final response = await http.get(
        'http://api.tianapi.com/generalnews/index?key=7ffbc5561c177f7d61b9c440ec0c6975&num=50&page=1');
    Utf8Decoder decode = new Utf8Decoder();
    Map<String, dynamic> result = jsonDecode(decode.convert(response.bodyBytes));
    //print(result);
    List<CommonModel> datas; //转列表
    datas = result['newslist'].map<CommonModel>((item) => CommonModel.fromJson(item)).toList();
    return datas; //返回 初始化
  }

2.建立新闻类

代码如下(示例):
此处可以根据天行网说明建立类的相关属性
在这里插入图片描述

class CommonModel {
  int code;//状态编码
  String msg;//状态信息
  String ctime;//时间
  String title;//标题
  String description;//再看
  String picUrl;//来源
  String url;//url

  CommonModel({this.code,this.msg,this.ctime, this.title, this.description,this.picUrl,this.url});

  factory CommonModel.fromJson(Map<String, dynamic> json) {
    return CommonModel(
        code: json['code'],
        msg: json['msg'],
        ctime: json['ctime'],
        title: json['title'],
        description: json['description'],
        picUrl: json['picUrl'],
        url: json['url']);
  }
}

3.获取了换回的json后就只需要构建布局即可,

 Widget build(BuildContext context) {
    var theme = Constants.currentTheme == Constants.dayTheme
        ? ThemeData(
        brightness: Brightness.light,
        primaryColor: Colors.blue,
        accentColor: Colors.orangeAccent)
        : ThemeData(
        brightness: Brightness.dark,
        primaryColor: Colors.black,
        accentColor: Colors.cyan);

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: theme,
        home: Scaffold(
          appBar: AppBar(
            leading: Icon(Icons.title),
            title: Text('新闻推送', style: TextStyle(color: Colors.white)),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.assignment),
                onPressed: (() {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => AboutPage()),
                  );
                }),
              ),
              IconButton(
                  icon: Icon(Icons.autorenew),
                  onPressed: (() {
                    Constants.eventBus.fire(//发送消息给main构建app
                        Constants.currentTheme == Constants.dayTheme ? ThemeEvent(Constants.nightTheme) : ThemeEvent(Constants.dayTheme));
                  }))
            ],
          ),
          body: Container(
            child: ListView.builder(
              itemCount: _datas.length,
              itemBuilder: (BuildContext context, int index) {
                  return Card(
                  color: Colors.grey[250],
                  elevation: 5.0,
                    child: InkWell(
                      child: new Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                        Image.network(_datas[index].picUrl, fit: BoxFit.fitWidth),
                         Padding(
                              padding: const EdgeInsets.all(10.0),
                              child: Text(
                                _datas[index].title,
                              style: TextStyle(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                              ),
                              ),
                         ),
                          Padding(
                            padding: _datas[index].description.isEmpty
                            ? const EdgeInsets.all(0.0)
                              : const EdgeInsets.only(
                            left: 10.0, right: 10.0, bottom: 10.0),
                            child: Text(
                              _datas[index].description,
                            style: TextStyle(
                            fontSize: 12.0,
                            ),
                            ),
                           ),
                          Padding(
                           padding: const EdgeInsets.only(left: 10.0, right: 10.0),
                            child: Text(
                          '时间:${_datas[index].ctime}',
                          style: TextStyle(
                          fontSize: 12.0,
                          ),
                          ),
                          ),
                          ],
                          ),
                          onTap: () {
                          _onItemClick(index, _datas[index]);
                          },
                          ),
                  );

              },
            ),
          ),
        )
    );
  }

3.新闻详情页面

在我们的新闻卡片列表中设置一个点击时间,点击后调用函数,进入新闻详情页面的新路由即可。
处理点击事件的函数

//新闻详情
  _onItemClick(int position, CommonModel data) {
    if (data.url == null || data.url.isEmpty) {
      Scaffold.of(context).showSnackBar(SnackBar(
        content: new Text('缺少新闻链接'),
        duration: Duration(seconds: 1),
      ));
    } else {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (ctx) => NewsDetailPage(
            url: data.url,
            title:data.title,
          )));
    }
  }

新闻详情页面使用webwiew插件,实现在自己的项目中,根据url请求网页
在这里插入图片描述

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
class NewsDetailPage extends StatefulWidget {
  final String url;
  final String title;

  const NewsDetailPage({Key key, this.url, this.title})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => NewsDetailPageState();
}

class NewsDetailPageState extends State<NewsDetailPage> {
  bool loaded = false;
  String detailDataStr;
  final flutterWebViewPlugin = FlutterWebviewPlugin();

  NewsDetailPageState({Key key});

  @override
  void initState() {
    super.initState();
    flutterWebViewPlugin.onStateChanged.listen((state) {
      print("state: ${state.type}");
      if (state.type == WebViewState.finishLoad) {
        setState(() {
          loaded = true;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {

    List<Widget> titleContent = [];
    titleContent.add(Text(
      widget.title,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(
          fontSize: 13.0
      ),
      )
    );
    if (!loaded) {
      titleContent.add(CupertinoActivityIndicator());
    }
    titleContent.add(Container(width: 50.0));
    return WebviewScaffold(
      url: widget.url,
      appBar: AppBar(
        title: Expanded(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: titleContent,
          ),
        )
      ),
      withZoom: false,
      withLocalStorage: true,
      withJavascript: true,
    );
  }
}

总结

项目总体结构
在这里插入图片描述
http_news.dart


import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import'NewsDetailPage.dart';
import 'AboutPage.dart';
import 'Constants.dart';
class qimo extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<qimo> {
  int lenth;
  String ctime;
  String title;
  String description;
  String picUrl;
  String url;
  List<CommonModel> _datas = [];
  bool _cancelConnect = false; //多次请求!

  @override
  void initState() {
    super.initState();
    Constants.eventBus.on<ThemeEvent>().listen((event) {
      setState(() {
        //TODO 应该添加至SP中持久化,待下次进入时使用
        Constants.currentTheme = event.themeModel;
      });
    });
    getDatas().then((List<CommonModel> datas) {
      if(!_cancelConnect){
        setState(() {
          _datas = datas; //初始化state 重新刷新页面
        });
      }
    }).catchError((e) {
      print('error$e');
    }).whenComplete((){
      print('完毕');
    }).timeout(Duration(seconds: 1)).catchError((timeOut){
      //超时:TimeoutException after 0:00:00.010000: Future not completed
      print('超时:${timeOut}');
      _cancelConnect = true;
    });//设置超时时间
  }
  //get请求
  Future<List<CommonModel>> getDatas() async {
    final response = await http.get(
        'http://api.tianapi.com/generalnews/index?key=7ffbc5561c177f7d61b9c440ec0c6975&num=50&page=1');
    Utf8Decoder decode = new Utf8Decoder();
    Map<String, dynamic> result = jsonDecode(decode.convert(response.bodyBytes));
    //print(result);
    List<CommonModel> datas; //转列表
    datas = result['newslist'].map<CommonModel>((item) => CommonModel.fromJson(item)).toList();
    return datas; //返回 初始化
  }

  //新闻详情
  _onItemClick(int position, CommonModel data) {
    if (data.url == null || data.url.isEmpty) {
      Scaffold.of(context).showSnackBar(SnackBar(
        content: new Text('缺少新闻链接'),
        duration: Duration(seconds: 1),
      ));
    } else {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (ctx) => NewsDetailPage(
            url: data.url,
            title:data.title,
          )));
    }
  }


  @override
  Widget build(BuildContext context) {
    var theme = Constants.currentTheme == Constants.dayTheme
        ? ThemeData(
        brightness: Brightness.light,
        primaryColor: Colors.blue,
        accentColor: Colors.orangeAccent)
        : ThemeData(
        brightness: Brightness.dark,
        primaryColor: Colors.black,
        accentColor: Colors.cyan);

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: theme,
        home: Scaffold(
          appBar: AppBar(
            leading: Icon(Icons.title),
            title: Text('新闻推送', style: TextStyle(color: Colors.white)),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.assignment),
                onPressed: (() {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => AboutPage()),
                  );
                }),
              ),
              IconButton(
                  icon: Icon(Icons.autorenew),
                  onPressed: (() {
                    Constants.eventBus.fire(//发送消息给main构建app
                        Constants.currentTheme == Constants.dayTheme ? ThemeEvent(Constants.nightTheme) : ThemeEvent(Constants.dayTheme));
                  }))
            ],
          ),
          body: Container(
            child: ListView.builder(
              itemCount: _datas.length,
              itemBuilder: (BuildContext context, int index) {
                  return Card(
                  color: Colors.grey[250],
                  elevation: 5.0,
                    child: InkWell(
                      child: new Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                        Image.network(_datas[index].picUrl, fit: BoxFit.fitWidth),
                         Padding(
                              padding: const EdgeInsets.all(10.0),
                              child: Text(
                                _datas[index].title,
                              style: TextStyle(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                              ),
                              ),
                         ),
                          Padding(
                            padding: _datas[index].description.isEmpty
                            ? const EdgeInsets.all(0.0)
                              : const EdgeInsets.only(
                            left: 10.0, right: 10.0, bottom: 10.0),
                            child: Text(
                              _datas[index].description,
                            style: TextStyle(
                            fontSize: 12.0,
                            ),
                            ),
                           ),
                          Padding(
                           padding: const EdgeInsets.only(left: 10.0, right: 10.0),
                            child: Text(
                          '时间:${_datas[index].ctime}',
                          style: TextStyle(
                          fontSize: 12.0,
                          ),
                          ),
                          ),
                          ],
                          ),
                          onTap: () {
                          _onItemClick(index, _datas[index]);
                          },
                          ),
                  );

              },
            ),
          ),
        )
    );
  }
}

class CommonModel {
  int code;//状态编码
  String msg;//状态信息
  String ctime;//时间
  String title;//标题
  String description;//再看
  String picUrl;//来源
  String url;//url

  CommonModel({this.code,this.msg,this.ctime, this.title, this.description,this.picUrl,this.url});

  factory CommonModel.fromJson(Map<String, dynamic> json) {
    return CommonModel(
        code: json['code'],
        msg: json['msg'],
        ctime: json['ctime'],
        title: json['title'],
        description: json['description'],
        picUrl: json['picUrl'],
        url: json['url']);
  }
}
class ThemeEvent extends IEvent{
  int themeModel;

  ThemeEvent(int themeModel) : super(""){
    this.themeModel = themeModel;
  }
}
class IEvent{
  String id;
  IEvent(String id): this.id = id;
}

AboutPage.dart

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'Newsdetailpage.dart';

class AboutPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("关于"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              FlutterLogo(
                size: 55.0,
              ),
              Container(
                padding: EdgeInsets.all(5.0),
              ),
              Text('作者:QYK',
                  style:
                  TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
              Container(
                padding: EdgeInsets.all(5.0),
              ),
              GestureDetector(
                child: Text(
                  'CSDN',
                  style: TextStyle(
                      color: Colors.blueAccent,
                      decoration:
                      TextDecoration.combine([TextDecoration.underline])),
                ),
                onTap: () {
                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (ctx) => NewsDetailPage(

                      )));
                },
              )
            ],
          ),
        ));
  }
}

NewsDetailPageState.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
class NewsDetailPage extends StatefulWidget {
  final String url;
  final String title;

  const NewsDetailPage({Key key, this.url, this.title})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => NewsDetailPageState();
}

class NewsDetailPageState extends State<NewsDetailPage> {
  bool loaded = false;
  String detailDataStr;
  final flutterWebViewPlugin = FlutterWebviewPlugin();

  NewsDetailPageState({Key key});

  @override
  void initState() {
    super.initState();
    flutterWebViewPlugin.onStateChanged.listen((state) {
      print("state: ${state.type}");
      if (state.type == WebViewState.finishLoad) {
        setState(() {
          loaded = true;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {

    List<Widget> titleContent = [];
    titleContent.add(Text(
      widget.title,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(
          fontSize: 13.0
      ),
      )
    );
    if (!loaded) {
      titleContent.add(CupertinoActivityIndicator());
    }
    titleContent.add(Container(width: 50.0));
    return WebviewScaffold(
      url: widget.url,
      appBar: AppBar(
        title: Expanded(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: titleContent,
          ),
        )
      ),
      withZoom: false,
      withLocalStorage: true,
      withJavascript: true,
    );
  }
}

Constant.dart

import 'package:event_bus/event_bus.dart';

class Constants {

  //全局的event_bus
  static final EventBus eventBus = EventBus();
  // ______________________________________________
  //当前的主题模式
  static int currentTheme = dayTheme;
  //日间模式
  static final int dayTheme = 1;
  //  //夜间模式
  static final int nightTheme = 2;
// ______________________________________________

}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Flutter 是一种开源的跨平台移动应用开发框架,它由谷歌开发。使用 Flutter,开发者可以使用一套代码编写适用于iOS和Android的应用程序,这样可以大大提高开发效率。 Flutter 项目是指基于 Flutter 框架进行开发的移动应用项目Flutter 项目可以在一台开发者的电脑上进行开发,并通过编写控制台命令将应用程序打包成适用于不同操作系统的应用文件。 Flutter 项目具有以下特点: 1. 快速开发:Flutter 使用 Dart 语言编写代码,具有热重载功能,可以快速预览应用程序的更改效果。 2. 跨平台:Flutter 可以生成原生的应用程序,它具有相同的性能和外观体验,无论是在 iOS 还是 Android 平台上运行。 3. 自定义 UI:Flutter 提供了丰富的 UI 组件和材料设计风格的控件,开发者可以自定义UI界面,使应用程序与众不同。 4. 性能优化:Flutter 的渲染引擎可以直接绘制界面,提供高性能的渲染效果,使应用程序运行流畅。 5. 第三方插件支持:Flutter 支持丰富的第三方插件,可以快速实现各种功能,如地图、支付、数据存储等。 6. 社区活跃:Flutter 拥有庞大的开发者社区,可以快速获取解决问题的答案和支持。 总之,Flutter 项目是使用 Flutter 框架进行开发的移动应用项目,具有快速开发、跨平台、自定义 UI、性能优化和社区活跃等特点。在移动应用开发领域,Flutter 项目具有巨大的发展潜力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值