Flutter 轮播组件 flutter_swiper 以及 Dio.dart请求包的使用

flutter_swiper和dio的引入

flutter_swiper组件作为第三方组件,我们需要通过在github上找到并通过pubspec.yaml文件进行引入安装,dio也同一样,在github中搜索dio就可以看到对应的文档

image.png

接下来,根据德阳旅游资讯网的移动端H5页面,我们开发一个app首页.大致效果如下:


image.png

页面包管理引入

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:dio/dio.dart';
dart:convert

我们要使用dio返回的数据类型,把String类型转换成Map类型,或者把Map类型转换成String类型需要使用到下面2个函数
json.decode() - 把String类型转换成Map类型,方便我们后面对json数据的使用
json.encode() - 把Map类型转换成String类型
如果需要用到这2个函数进行转换,那么久需要引入dart:convert包,如果不引入,我们也可以通过在vscode编译器中点击快速修复,编译器会给我们添加上这个包.

image.png

flutter/material.dart

这个没什么好特别介绍的,安卓界面ui组件库

flutter_swiper/flutter_swiper.dart

刚才在pubspec.yaml文件中引入安装的flutter_swiper组件.引入后,我们才可以使用SwiperWidget()组件

dio/dio.dart

非常好用的请求组件,简单好用.具体参考github文档进行使用

建立入口函数及简单布局

根据前面的图,我们大致把页面分为3个部分

  • 顶部banner轮播图
  • 按钮导航区域
  • 新闻列表区域
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flutter_swiper',
      home: Scaffold(
        appBar: AppBar(
          title: Text('德阳旅游资讯网'),
        ),
        body: Container(
          child: Column(
            children: [
              // - 第一部分:banner轮播区域
              Container(
                height: 200.0,
                child: Padding(
                    padding: EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
                    child: SwiperWidget()),
              ),
              // - 第二部分:导航按钮区域
              Container(height: 150.0, child: IndexNav()),
              //- 新闻列表区域
              NewsList(),
            ],
          ),
        ),
      ),
    );
  }
}

轮播组件开发

这里我们由于使用了dio进行请求,数据需要异步渲染,定义的SwiperWidget组件需要继承StatefulWidget,定义一个List类型的dataList作为组件数据渲染的数据模型.获取数据之后通过setState()函数让flutter的widget再次渲染
这里需要注意dataList再获取数据之前是一个空的数组,所以渲染时做一个length判断,在数据没有加载出来之前,我们使用一个文本加载中进行填充轮播位置,否则会出现轮播在初始渲染时显示不正常的情况.当然也可以使用其他图片的形式代替加载等待.

//- 轮播
class SwiperWidget extends StatefulWidget {
  SwiperWidget({Key key}) : super(key: key);
  @override
  _SwiperWidgetState createState() => _SwiperWidgetState();
}
class _SwiperWidgetState extends State {
  String url =
      'https://sczxw.hzcloud.daqsoft.com/frontrest/index';
  var params = {
    'method': 'bannerList',
    'appkey': 'dygly',
    'channelCode': 'zydy',
    'row': 4,
    'page':1,
    'apppwd': 'daqsoft'
  };
  List dataList = [];
  @override
  void initState() {
    super.initState();
    getHttp(this.url, params).then((res) {
      setState(() {
        this.dataList = json.decode(res.toString())['data']['rows'];
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return this.dataList.length > 0
        ? Swiper(
            itemBuilder: (BuildContext context, int index) {
              return new Image.network(
                this.dataList[index]['path'],
                fit: BoxFit.cover,
              );
            },
            index: 0,
            itemCount: this.dataList.length,
            pagination: new SwiperPagination(),
            // control: new SwiperControl(),
          )
        : Text('加载中...');
  }
}

导航按钮区域

导航按钮由于内容是定死的,并不需要接口来配置.我们可以使用一个List类型的变量来作为配置

final List navList = [
    {
      'id': 1,
      'name': '乡村游',
      'icon': Icons.nature_people,
      'color': Colors.orange[300]
    },
    {
      'id': 2,
      'name': '景区景点',
      'icon': Icons.filter_hdr,
      'color': Colors.blue[300]
    },
    {
      'id': 3,
      'name': '酒店住宿',
      'icon': Icons.local_hotel,
      'color': Colors.red[300]
    },
    {
      'id': 4,
      'name': '特色美食',
      'icon': Icons.local_dining,
      'color': Colors.orange[300]
    },
    {
      'id': 5,
      'name': '特色购物',
      'icon': Icons.shopping_cart,
      'color': Colors.orange[300]
    },
    {'id': 6, 'name': '休闲娱乐', 'icon': Icons.rowing, 'color': Colors.green[300]},
    {
      'id': 7,
      'name': '推荐线路',
      'icon': Icons.call_split,
      'color': Colors.lightGreenAccent[300]
    },
    {
      'id': 8,
      'name': '旅游攻略',
      'icon': Icons.border_color,
      'color': Colors.red[300]
    },
  ];

有了导航按钮配置,接下来我们开始发开对应的导航按钮区域这个组件
我们通过GridView.builder组件来构建一个网格布局来实现导航按钮区域,导航按钮区域的组件的完整代码如下:

//- 页面导航
class IndexNav extends StatelessWidget {
  final List navList = [
    {
      'id': 1,
      'name': '乡村游',
      'icon': Icons.nature_people,
      'color': Colors.orange[300]
    },
    {
      'id': 2,
      'name': '景区景点',
      'icon': Icons.filter_hdr,
      'color': Colors.blue[300]
    },
    {
      'id': 3,
      'name': '酒店住宿',
      'icon': Icons.local_hotel,
      'color': Colors.red[300]
    },
    {
      'id': 4,
      'name': '特色美食',
      'icon': Icons.local_dining,
      'color': Colors.orange[300]
    },
    {
      'id': 5,
      'name': '特色购物',
      'icon': Icons.shopping_cart,
      'color': Colors.orange[300]
    },
    {'id': 6, 'name': '休闲娱乐', 'icon': Icons.rowing, 'color': Colors.green[300]},
    {
      'id': 7,
      'name': '推荐线路',
      'icon': Icons.call_split,
      'color': Colors.lightGreenAccent[300]
    },
    {
      'id': 8,
      'name': '旅游攻略',
      'icon': Icons.border_color,
      'color': Colors.red[300]
    },
  ];
  Widget _getNavListData(context, index) {
    return Container(
      child: Column(
        children: [
          CircleAvatar(
            backgroundColor: this.navList[index]['color'],
            child: Icon(
              this.navList[index]['icon'],
              color: Colors.white,
            ),
          ),
          SizedBox(height: 4.0),
          Text(
            this.navList[index]['name'],
            style: TextStyle(fontSize: 12),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisSpacing: 20.0, //- 水平子Widget 之间间距
          mainAxisSpacing: 20.0, //- 垂直子Widget 之间间距
          crossAxisCount: 4, //- 一行的Widget 数量,
          childAspectRatio: 1.2, //- 设置宽度和高度的比例
        ),
        itemCount: this.navList.length,
        itemBuilder: _getNavListData);
  }
}

新闻列表区域

经过前面对dio的使用,我们只需要读取接口,简单的对页面渲染.即可,只需要注意数据更新使用setState()进行更新,才能够让flutter重新渲染页面.

//- 新闻列表
class NewsList extends StatefulWidget {
  NewsList({Key key}) : super(key: key);

  @override
  _NewsListState createState() => _NewsListState();
}

class _NewsListState extends State {
  var params = {
    'method': 'newsList',
    'appkey': 'dygly',
    'channelCode': 'zydy',
    'row': 4,
    'page': 1,
    'apppwd': 'daqsoft'
  };
  String url = 'https://sczxw.hzcloud.daqsoft.com/frontrest/welcome';
  List newsList = [];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getHttp(url, params).then((res) {
      List tempList = json.decode(res.toString())['data']['rows'];
      
      for(var i = 0; i < tempList.length; i++) {
        tempList[i]['img'] = tempList[i]['imgs'].split(',');
      }
      setState(() {
        this.newsList = tempList;
      });
      print(this.newsList);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: ListView(
        children: this.newsList.map((val) {
          return ListTile(
            leading: Image.network(val['img'][0], width: 80.0, height: 40.0, fit:BoxFit.cover),
            title: Text(val['titcont'], overflow: TextOverflow.ellipsis,maxLines: 2,style:TextStyle(fontSize: 14))
          );
      }).toList(),),
    );
  }
}

Dio网络请求

最后我们来简单对上面demo中的请求做一个讲解.
下面的代码是按照github上的demo进行修改的,主要是调用了Dio().get()方法使用get请求,同时在里面传入2个参数,一个是url(请求地址),一个是queryParameters请求参数

//- 请求
getHttp(url, params) async {
  try {
    Response response = await Dio().get(url, queryParameters: params);
    return response;
  } catch (e) {
    print(e);
    return e;
  }
}

这里需要注意的是dart的异步语法,由于Dio().get(url,queryParameters)自身本来就是一个异步请求,所以我们这里需要用到asyncawait来等待请求的结果,再把数据return出去.
调用的时候只需要:

 getHttp(url, params).then((res) {})

该文里的内容完整代码如下:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:dio/dio.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flutter_swiper',
      home: Scaffold(
        appBar: AppBar(
          title: Text('德阳旅游资讯网'),
        ),
        body: Container(
          child: Column(
            children: [
              Container(
                height: 200.0,
                child: Padding(
                    padding: EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
                    child: SwiperWidget()),
              ),
              Container(height: 150.0, child: IndexNav()),
              NewsList(),
            ],
          ),
        ),
      ),
    );
  }
}

//- 轮播
class SwiperWidget extends StatefulWidget {
  SwiperWidget({Key key}) : super(key: key);
  @override
  _SwiperWidgetState createState() => _SwiperWidgetState();
}

class _SwiperWidgetState extends State {
  String url =
      'https://sczxw.hzcloud.daqsoft.com/frontrest/index';
  var params = {
    'method': 'bannerList',
    'appkey': 'dygly',
    'channelCode': 'zydy',
    'row': 4,
    'page':1,
    'apppwd': 'daqsoft'
  };
  List dataList = [];
  @override
  void initState() {
    super.initState();
    getHttp(this.url, params).then((res) {
      setState(() {
        this.dataList = json.decode(res.toString())['data']['rows'];
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return this.dataList.length > 0
        ? Swiper(
            itemBuilder: (BuildContext context, int index) {
              return new Image.network(
                this.dataList[index]['path'],
                fit: BoxFit.cover,
              );
            },
            index: 0,
            itemCount: this.dataList.length,
            pagination: new SwiperPagination(),
            // control: new SwiperControl(),
          )
        : Text('加载中...');
  }
}

//- 页面导航
class IndexNav extends StatelessWidget {
  final List navList = [
    {
      'id': 1,
      'name': '乡村游',
      'icon': Icons.nature_people,
      'color': Colors.orange[300]
    },
    {
      'id': 2,
      'name': '景区景点',
      'icon': Icons.filter_hdr,
      'color': Colors.blue[300]
    },
    {
      'id': 3,
      'name': '酒店住宿',
      'icon': Icons.local_hotel,
      'color': Colors.red[300]
    },
    {
      'id': 4,
      'name': '特色美食',
      'icon': Icons.local_dining,
      'color': Colors.orange[300]
    },
    {
      'id': 5,
      'name': '特色购物',
      'icon': Icons.shopping_cart,
      'color': Colors.orange[300]
    },
    {'id': 6, 'name': '休闲娱乐', 'icon': Icons.rowing, 'color': Colors.green[300]},
    {
      'id': 7,
      'name': '推荐线路',
      'icon': Icons.call_split,
      'color': Colors.lightGreenAccent[300]
    },
    {
      'id': 8,
      'name': '旅游攻略',
      'icon': Icons.border_color,
      'color': Colors.red[300]
    },
  ];
  Widget _getNavListData(context, index) {
    return Container(
      child: Column(
        children: [
          CircleAvatar(
            backgroundColor: this.navList[index]['color'],
            child: Icon(
              this.navList[index]['icon'],
              color: Colors.white,
            ),
          ),
          SizedBox(height: 4.0),
          Text(
            this.navList[index]['name'],
            style: TextStyle(fontSize: 12),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisSpacing: 20.0, //- 水平子Widget 之间间距
          mainAxisSpacing: 20.0, //- 垂直子Widget 之间间距
          crossAxisCount: 4, //- 一行的Widget 数量,
          childAspectRatio: 1.2, //- 设置宽度和高度的比例
        ),
        itemCount: this.navList.length,
        itemBuilder: _getNavListData);
  }
}

//- 新闻列表
class NewsList extends StatefulWidget {
  NewsList({Key key}) : super(key: key);

  @override
  _NewsListState createState() => _NewsListState();
}

class _NewsListState extends State {
  var params = {
    'method': 'newsList',
    'appkey': 'dygly',
    'channelCode': 'zydy',
    'row': 4,
    'page': 1,
    'apppwd': 'daqsoft'
  };
  String url = 'https://sczxw.hzcloud.daqsoft.com/frontrest/welcome';
  List newsList = [];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getHttp(url, params).then((res) {
      List tempList = json.decode(res.toString())['data']['rows'];
      
      for(var i = 0; i < tempList.length; i++) {
        tempList[i]['img'] = tempList[i]['imgs'].split(',');
      }
      setState(() {
        this.newsList = tempList;
      });
      print(this.newsList);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: ListView(
        children: this.newsList.map((val) {
          return ListTile(
            leading: Image.network(val['img'][0], width: 80.0, height: 40.0, fit:BoxFit.cover),
            title: Text(val['titcont'], overflow: TextOverflow.ellipsis,maxLines: 2,style:TextStyle(fontSize: 14))
          );
      }).toList(),),
    );
  }
}

//- 请求
getHttp(url, params) async {
  try {
    Response response = await Dio().get(url, queryParameters: params);
    return response;
  } catch (e) {
    print(e);
    return e;
  }
}

你可能感兴趣的:(Flutter 轮播组件 flutter_swiper 以及 Dio.dart请求包的使用)