當咱們搭建好了整個APP的頁面框架,如今我往Tab頁里加點東西:各類分類的新聞列表。也能夠參考個人Git,上面有要點註釋。html
因爲須要請求外部數據,所以引入一個較爲方便的http庫。官方示例的httpClient也是能夠的,可是坑略多,待會兒講。react
調整代碼結構,定義一個Tab
頁內通用的列表對象,這種場景下使用ListView.builder()
建立不定長度的列表:git
//由於列表的長度不定,所以須要用有狀態類來承載列表
class NewsList extends StatefulWidget{
final String newsType; //新聞類型
@override
NewsList({Key key, this.newsType} ):super(key:key);
_NewsListState createState() => new _NewsListState();
}
class _NewsListState extends State<NewsList>{
...
@override
Widget build(BuildContext context){
return new ListView.builder( //ListView.builder很是適合用於建立不肯定長度的的列表
padding: const EdgeInsets.all(16.0),
itemCount: data == null ? 0 : data.length,
itemBuilder: (context, i) {
return _newsRow(data[i]);//把數據項塞入ListView中
}
);
}
...
}
複製代碼
將Tab
頁的數據表達進行結構化處理,在最外層定義新聞Tab
頁的類,方便後面使用:github
//定義TAB頁對象,這樣作的好處就是,能夠靈活定義每一個tab頁用到的對象,可結合Iterable對象使用,之後講
class NewsTab {
String text;
NewsList newsList;
NewsTab(this.text,this.newsList);
}
複製代碼
到**_MyTabbedPageState**對象中實例化這些Tab
:數組
//將每一個Tab頁都結構化處理下,因爲http的請求須要傳入新聞類型的參數newsType,所以將新聞類型參數值做爲對象屬性傳入Tab中
final List<NewsTab> myTabs = <NewsTab>[
new NewsTab('頭條',new NewsList(newsType: 'toutiao')), //拼音就是參數值
new NewsTab('社會',new NewsList(newsType: 'shehui')),
new NewsTab('國內',new NewsList(newsType: 'guonei')),
new NewsTab('國際',new NewsList(newsType: 'guoji')),
new NewsTab('娛樂',new NewsList(newsType: 'yule')),
new NewsTab('體育',new NewsList(newsType: 'tiyu')),
new NewsTab('軍事',new NewsList(newsType: 'junshi')),
new NewsTab('科技',new NewsList(newsType: 'keji')),
new NewsTab('財經',new NewsList(newsType: 'caijing')),
new NewsTab('時尚',new NewsList(newsType: 'shishang')),
];
複製代碼
因爲從新了Tabs,原來的TabBar和TabBarView獲取對應值的方式也發生了改變,用map
+toList
方法處理下:app
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
backgroundColor: Colors.orangeAccent,
title: new TabBar(
controller: _tabController,
tabs: myTabs.map((NewsTab item){ //NewsTab能夠不用聲明
return new Tab(text: item.text==null?'錯誤':item.text);
}).toList(), //記住要用toList()轉換一下map的結果,不然會因爲類型不匹配而報錯
indicatorColor: Colors.white,
isScrollable: true, //水平滾動的開關,開啓後Tab標籤可自適應寬度並可橫向拉動,並自動從左到右排列,默認關閉
),
),
body: new TabBarView(
controller: _tabController,
children: myTabs.map((item) {
return item.newsList; //使用參數值
}).toList(),
),
);
}
複製代碼
以上對新聞頁面的結構進行了重構,重頭戲就是完善NewsList對象。因而乎,在初始化NewsList對象時發起HTTP請求應該是個不錯的辦法:框架
具體是怎麼初始化數據的,第三步會講到,踩了很多坑。這裏的重點是,Flutter提倡數據驅動組件的建立,組件本身沒法觸發動態建立對象,只有經過數據綁定的方式,實現對象的重繪和動態加載,原理和react相似,好比:異步
到了這一步,徹底進入踩坑模式。ide
Future<String>
,返回值也須要await
異步處理後才能夠轉換成須要的數據類型:上圖中列舉了兩種方法,建議使用下面那種,由於若是能從返回值中提取請求獲取的數據,便可將全部的http請求封裝到API文件中去,沒必要寫在頁面代碼中,緣由你們都懂的。 注意在setState()
以前有一句if(!mounted) return
,由於異步請求數據和控件的渲染是同時進行的,若是代碼已經執行到了setState
,可是數據尚未獲取到,此時setState
觸發的控件渲染就會報錯,爲了不這種空值錯誤,在setState
以前先判斷空間是否已經渲染完成,mounted
即Flutter內置的當前控件的狀態標識,記住就好。函數
圖中的提示說使用Flexible控件更佳,然而實際上Flexible也會報錯。報錯的英文大概意思是ListView控件生成未知長度的列表時,老是會自動壓縮每個子元素的高度,而Expanded和Flexible都是能夠自由伸縮的控件,形成ListView的子元素沒法肯定繪製的高度,爲了使超出屏幕寬度的新聞標題自動換行,這個時候用ListTile頂替一下吧。
如上圖,確定是不行的,控件的子元素是不容許爲空的,因而使用條件判斷的方式封裝一下:
map
數組和Object
數組的使用,newsinfo.["title"]
和newsinfo.title
二者的newsinfo
類型是不同的,詳細仍是到源碼中去體會吧,注意對比newsinfo
和myTab
這兩個的用法。此次頁面寫的很是辛苦,並且還沒實現滾動刷新或頂部下拉刷新的效果,下一篇再更吧,還有不少要點我在源碼中有標識,能夠去個人Git中慢慢品味,今天就更到這裏,滾去睡覺,真的來不起了。
感謝你們的支持,請關注個人Flutter圈子,多多投稿,也能夠加入**flutter 中文社區(官方QQ羣:338252156)**共同成長,謝謝你們~