Flutter开发 项目实战02

接着上篇

这篇最主要的是:

  1. GridView (flutter的横向列表,相对于iOS的UICollectionView)

  2. httpClient (flutter的网络请求,暂时会简单的数据处理,关于数据模型化还没未到更快捷的方法,需要硬敲出来,没有类似iOS中的YYModel一样,直接一套)

3. 页面的跳转并传参(上下级页面通常需要传递参数,类似详情页,可以减少网络请求的次数)

  1. flutter_refresh(flutter的一个上拉刷新下拉加载的插件,调用很简单,关于自定义刷新动画还需要更多的去了解,顺便介绍关于根据条件来动态布局)

1. Flutter的横向列表GridView

flutter中横向列表类似iOS中的UICollectionView的是GridView,开发前我没有了解到这个控件,对于行数不多的,我直接使用listview自定义item硬写,当然复制代码也是很快的,但是当然需要更可塑性的布局方式。看下面这张图我的页面中的示例。

我的页面
image

这个页面总体是个ListView,对应的是每个item,其中红框就是个GridView,以下是创建GridView的代码


//GridView的创建代码

doubleItemWidth= ScreenWidth /4.0;

doubleItemHeight=70.0;

var cellItemMiddleInfo =new GestureDetector(

onTap: ()=>{},

child:new Container(

width: ScreenWidth,

child:new Column(

children: [

new Container(

width: ScreenWidth,

height: SmallMiddleHeight *2.0,

color: Colors.white,

child:new GridView.builder(

gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(

mainAxisSpacing:0.0,//竖向间距

//                    crossAxisCount: 4,//横向Item的个数

                      maxCrossAxisExtent: ScreenWidth/4.0,

crossAxisSpacing:0.0,//横向间距

                      childAspectRatio:(ItemWidth/ItemHeight)

),

primary:false,

itemCount: List2.length,

itemBuilder: MyItemImageText,

)

),

new Divider(height:1.0,),

new Container(

width: ScreenWidth,

height:15.0,

),

new Divider(height:1.0,),

],

)

),

);

//GridView也需要子item,这是子item的代码

////////中间部分的操作栏 私密文章 我的收藏 我的喜欢 等

WidgetMyItemImageText(BuildContext context, int index) {

doubleScreenWidth= MediaQuery.of(context).size.width;

doubleItemWidth= ScreenWidth /4.0;

doubleItemHeight=70.0;

var Item=new GestureDetector(

onTap: (){},

child:new Container(

width: ItemWidth,

height: ItemHeight,

//      color: Colors.red,

      child:new Column(

children: [

///顶部 图片

          new Container(

alignment: Alignment.center,

margin:new EdgeInsets.only(left:10.0, right:10.0, top:14.0),

height:18.0,

child:new Container(

alignment: Alignment.center,

height:18.0,

width:18.0,

child:new Image.asset(List2[index].itemImageSrc),

)

),

//底部的text

          new Container(

alignment: Alignment.center,

margin:new EdgeInsets.only(left:10.0, right:10.0, top:7.0),

height:15.0,

child:new Text(List2[index].downText, style:new TextStyle(fontSize:12.0, color:new Color.fromARGB(255,123,123,123)), softWrap:false, overflow: TextOverflow.ellipsis),

),

],

),

),

);

return Item;

}

工具类

以上就可以实现一个横向的GridView,我相信阅览了代码后也知道如何使用,其中childAspectRatio属性是用来设置item宽高比的,如果不设置默认宽高一样。

2. Flutter的网络请求


ListdataSource;

void _httpClient(var page)async {

var responseBody;

var httpClient =new HttpClient();

var request =await httpClient.getUrl(

Uri.parse("https://www.apiopen.top/satinGodApi?type=1&page=${page}"));

var response =await request.close();

print(page);

if (response.statusCode ==200) {

responseBody =await response.transform(utf8.decoder).join();

ListnewData = jsonDecode(responseBody)["data"];

if(page ==1 &&dataSource !=null) {

dataSource.clear();

}

//更新数据

    setState(() {

if(page ==1) {

dataSource = newData;

}else {

for (int a =0; a

dataSource.add(newData[a]);

}

}

});

}else {

print("error");

}

}

还要包含两个头文件哦


import 'dart:io';

import 'dart:convert';

页面一进去的话在这里调用


void initState() {

super.initState();

_httpClient(PAGE);

}

其中setState这个方法刷新dataSource可以刷新页面,flutter会检测哪里用到了dataSource就会刷新那里的页面,关于数据的是数组直接[index] 是map里取值就直接["key"],当然你可以封装一个数组里面包含返回值的所有key,这样使用的时候就可以直接dataSource.key.key了,但是我这里没有,因为巨麻烦。等找到高效的方法后再去修改吧。

3. Flutter页面的跳转并传参

在开发中,很多情况下需要传递参数到下级页面,比如详情页,外部请求了一次,详情页就没有必要再请求一次,可以上级页面传过来使用。跳转页面根据Flutter的文档,routes的灵感来源于reactjs,routes可以翻译为路由,可以看到这种routes的思路在目前的设计中彼此借鉴,routes的思路不仅在前端流行,比如在vue、reactjs、Angular中用到,而且在后端应用中也非常成熟。

关于页面跳转的代码


////跳转段子详情

pushAnotherView(int index){

print(index);

Navigator.of(context).push(

new MaterialPageRoute(

builder: (BuildContext context) {

var data =dataSource[index];

return new JokeDetailPage(mapd: data);

}

)

);

}

////返回按钮

new FlatButton(

onPressed:(){

Navigator.pop(context);

},

color: Colors.white,

child:new Icon(Icons.keyboard_backspace,color: Colors.blue, ),

),

接下来看看页面之间如何传参数


////这是二级页面的接收的写法

class JokeDetailPageextends StatefulWidget {

 JokeDetailPage ({var key,this.mapd}):super(key:key);//接收从上一个页面传来的值

 var mapd;

@override

  _JokeDetailPageState createState() =>new _JokeDetailPageState(mapd,mapd);

}

class _JokeDetailPageStateextends State  {
    _JokeDetailPageState(var key,this.mapd);
    var mapd;

  @override
  void dispose() {
      super.dispose();
  }

  void initState() {
      super.initState();
  }

 @override

 Widget build(BuildContext context) {
        return new MaterialApp();
  }

}

我这里传的是个var类型的数据,也可以传其他数据类型的。在上级页面跳转的时候就可以有提示了


////跳转段子详情   其中index是点击某个item传过来的 

pushAnotherView(int index){
     print(index);
      Navigator.of(context).push(
          new MaterialPageRoute(
              builder: (BuildContext context) {
                    var data =dataSource[index];
                    return new JokeDetailPage(mapd: data);////这里就可以传递参数了
              }
        )
    );
}

4. flutter_refresh

一个上拉加载,下拉刷新的控件。这是个插件,所以我们需要在pubspec.yaml文件中添加这个插件及版本号,然后运行Packages get来拉到本地来,这个插件的链接地址:flutter_refresh。

添加插件

使用方法


////chiild直接就是Refresh 添加头部尾部刷新方法和UI即可
return new Container(
      child:dataSource!=null ?
      new Refresh(
            onFooterRefresh: onFooterRefresh,
            onHeaderRefresh: onHeaderRefresh,
            child:new ListView.builder(
                  itemCount:dataSource.length,
                  itemBuilder: buildCelljianyouquanItem1,
            )
      ) :
      new Container(child:new Text(tab.text)),
);

// 顶部刷新
Future onHeaderRefresh() {
    return new Future.delayed(new Duration(seconds:2), () {
          setState(() {
                PAGE =1;
                _httpClient(PAGE);
          });
  });
}

// 底部刷新
Future onFooterRefresh()async {
    return new Future.delayed(new Duration(seconds:2), () {
        setState(() {
            PAGE +=1;
            _httpClient(PAGE);
         });
   });
}

以上就可以实现基本的刷新页面了哦。

下拉刷新
上拉加载

这里图片加载用了一个插件transparent_image,占位符淡入图片。


child:new FadeInImage.memoryNetwork(
    alignment: Alignment.centerLeft,
    placeholder: kTransparentImage,
    image:dataSource[index]["thumbnail"],
    fit: BoxFit.cover,
)

还要介绍以下根据条件动态布局,这个我找了好久的资料没找到,可能找到的方向不对,看到代码后,原来如此,也很简单。就拿下面的一段代码来做示列。


return new Container(
  child:dataSource!=null ?
      new Refresh(
          onFooterRefresh: onFooterRefresh,
          onHeaderRefresh: onHeaderRefresh,
          child:new ListView.builder(
          itemCount:dataSource.length,
          itemBuilder: buildCelljianyouquanItem1,
      )
  ):new Container(child:new Text(tab.text)),
);

这里我返回的Container根据了dataSource来判断,如果dataSource有值说明可以创建Listview刷新页面显示数据了,但是如果为空的话就返回一个居中的文本,显示正在加载中。一个简单的三目运算就可以完成根据数据来布局,这种用法贯穿了很多的布局。所以要Get哦。

最后附上Github上的Demo的地址:Demo传送门

还有开放API的地址:开放API

还有学习网站:

Flutter中文网

Flutter社区中文资源

如有不正确的地方帮忙指出,谢谢。

你可能感兴趣的:(Flutter开发 项目实战02)