接著上篇
這篇最主要的是:
GridView (flutter的橫向列表,相對(duì)于iOS的UICollectionView)
httpClient (flutter的網(wǎng)絡(luò)請(qǐng)求,暫時(shí)會(huì)簡(jiǎn)單的數(shù)據(jù)處理,關(guān)于數(shù)據(jù)模型化還沒未到更快捷的方法,需要硬敲出來,沒有類似iOS中的YYModel一樣,直接一套)
3. 頁面的跳轉(zhuǎn)并傳參(上下級(jí)頁面通常需要傳遞參數(shù),類似詳情頁,可以減少網(wǎng)絡(luò)請(qǐng)求的次數(shù))
- flutter_refresh(flutter的一個(gè)上拉刷新下拉加載的插件,調(diào)用很簡(jiǎn)單,關(guān)于自定義刷新動(dòng)畫還需要更多的去了解,順便介紹關(guān)于根據(jù)條件來動(dòng)態(tài)布局)
1. Flutter的橫向列表GridView
flutter中橫向列表類似iOS中的UICollectionView的是GridView,開發(fā)前我沒有了解到這個(gè)控件,對(duì)于行數(shù)不多的,我直接使用listview自定義item硬寫,當(dāng)然復(fù)制代碼也是很快的,但是當(dāng)然需要更可塑性的布局方式。看下面這張圖我的頁面中的示例。
這個(gè)頁面總體是個(gè)ListView,對(duì)應(yīng)的是每個(gè)item,其中紅框就是個(gè)GridView,以下是創(chuàng)建GridView的代碼
//GridView的創(chuàng)建代碼
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的個(gè)數(shù)
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;
}
以上就可以實(shí)現(xiàn)一個(gè)橫向的GridView,我相信閱覽了代碼后也知道如何使用,其中childAspectRatio屬性是用來設(shè)置item寬高比的,如果不設(shè)置默認(rèn)寬高一樣。
2. Flutter的網(wǎng)絡(luò)請(qǐng)求
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();
}
//更新數(shù)據(jù)
setState(() {
if(page ==1) {
dataSource = newData;
}else {
for (int a =0; a
dataSource.add(newData[a]);
}
}
});
}else {
print("error");
}
}
還要包含兩個(gè)頭文件哦
import 'dart:io';
import 'dart:convert';
頁面一進(jìn)去的話在這里調(diào)用
void initState() {
super.initState();
_httpClient(PAGE);
}
其中setState這個(gè)方法刷新dataSource可以刷新頁面,flutter會(huì)檢測(cè)哪里用到了dataSource就會(huì)刷新那里的頁面,關(guān)于數(shù)據(jù)的是數(shù)組直接[index] 是map里取值就直接["key"],當(dāng)然你可以封裝一個(gè)數(shù)組里面包含返回值的所有key,這樣使用的時(shí)候就可以直接dataSource.key.key了,但是我這里沒有,因?yàn)榫蘼闊?。等找到高效的方法后再去修改吧?/p>
3. Flutter頁面的跳轉(zhuǎn)并傳參
在開發(fā)中,很多情況下需要傳遞參數(shù)到下級(jí)頁面,比如詳情頁,外部請(qǐng)求了一次,詳情頁就沒有必要再請(qǐng)求一次,可以上級(jí)頁面?zhèn)鬟^來使用。跳轉(zhuǎn)頁面根據(jù)Flutter的文檔,routes的靈感來源于reactjs,routes可以翻譯為路由,可以看到這種routes的思路在目前的設(shè)計(jì)中彼此借鑒,routes的思路不僅在前端流行,比如在vue、reactjs、Angular中用到,而且在后端應(yīng)用中也非常成熟。
關(guān)于頁面跳轉(zhuǎn)的代碼
////跳轉(zhuǎn)段子詳情
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, ),
),
接下來看看頁面之間如何傳參數(shù)
////這是二級(jí)頁面的接收的寫法
class JokeDetailPageextends StatefulWidget {
JokeDetailPage ({var key,this.mapd}):super(key:key);//接收從上一個(gè)頁面?zhèn)鱽淼闹?
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();
}
}
我這里傳的是個(gè)var類型的數(shù)據(jù),也可以傳其他數(shù)據(jù)類型的。在上級(jí)頁面跳轉(zhuǎn)的時(shí)候就可以有提示了
////跳轉(zhuǎn)段子詳情 其中index是點(diǎn)擊某個(gè)item傳過來的
pushAnotherView(int index){
print(index);
Navigator.of(context).push(
new MaterialPageRoute(
builder: (BuildContext context) {
var data =dataSource[index];
return new JokeDetailPage(mapd: data);////這里就可以傳遞參數(shù)了
}
)
);
}
4. flutter_refresh
一個(gè)上拉加載,下拉刷新的控件。這是個(gè)插件,所以我們需要在pubspec.yaml文件中添加這個(gè)插件及版本號(hào),然后運(yùn)行Packages get來拉到本地來,這個(gè)插件的鏈接地址: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);
});
});
}
以上就可以實(shí)現(xiàn)基本的刷新頁面了哦。
這里圖片加載用了一個(gè)插件transparent_image,占位符淡入圖片。
child:new FadeInImage.memoryNetwork(
alignment: Alignment.centerLeft,
placeholder: kTransparentImage,
image:dataSource[index]["thumbnail"],
fit: BoxFit.cover,
)
還要介紹以下根據(jù)條件動(dòng)態(tài)布局,這個(gè)我找了好久的資料沒找到,可能找到的方向不對(duì),看到代碼后,原來如此,也很簡(jiǎn)單。就拿下面的一段代碼來做示列。
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根據(jù)了dataSource來判斷,如果dataSource有值說明可以創(chuàng)建Listview刷新頁面顯示數(shù)據(jù)了,但是如果為空的話就返回一個(gè)居中的文本,顯示正在加載中。一個(gè)簡(jiǎn)單的三目運(yùn)算就可以完成根據(jù)數(shù)據(jù)來布局,這種用法貫穿了很多的布局。所以要Get哦。
最后附上Github上的Demo的地址:Demo傳送門
還有開放API的地址:開放API
還有學(xué)習(xí)網(wǎng)站:
如有不正確的地方幫忙指出,謝謝。