本系列同步發表在 個人部落格,歡迎大家關注~
經過兩天的努力,終於能來修改頁面拉~
第二部份的更改頁面我想大家應該可以猜得到,一樣用 FutureBuilder
那一套囉~
lib/pages/trending/project.dart
import "package:flutter/material.dart";
import 'package:gitme_reborn/components/github_trending_tiles.dart';
import 'package:gitme_reborn/services/github_trending_api.dart';
import 'package:gitme_reborn/services/models/project.dart';
class TrendingProjects extends StatefulWidget {
@override
_TrendingProjectsState createState() => _TrendingProjectsState();
}
class _TrendingProjectsState extends State<TrendingProjects> {
Future<List<Project>> projectList;
@override
void initState() {
super.initState();
projectList = githubTrendingClient.listProjects();
}
@override
Widget build(BuildContext context) {
return Scrollbar(
child: RefreshIndicator(
child: FutureBuilder(
future: projectList,
builder:
(BuildContext context, AsyncSnapshot<List<Project>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if (!snapshot.hasError) {
return ListView.separated(
padding: EdgeInsets.all(0.0),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ProjectTile(
name: snapshot.data[index].fullName,
description: snapshot.data[index].description,
stars: snapshot.data[index].stars,
currentStars: snapshot.data[index].currentPeriodStars,
language: snapshot.data[index].language,
languageColor: snapshot.data[index].languageColor,
builtBy: snapshot.data[index].builtBy,
onPressed: () {},
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 0.0),
);
} else {
return Center(child: Text("No Data"));
}
break;
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
}
},
),
onRefresh: () async {
setState(() {
projectList = githubTrendingClient.listProjects();
});
},
),
);
}
}
lib/services/github_trending_api.dart
中宣告一個全域變數 GitHubTrendingApiClient githubTrendingClient = GitHubTrendingApiClient();
方便作使用。GitHubTrendingApiClient
方法 listProjects
和 listDevelopers
就可以了。ProjectTile
是自己封裝的 Widget,方便維護用。(程式碼在 lib/components/github_trending_tiles.dart
)不知道大家是否在 Day 10 時有注意到,其中畫面右上角的 PopupMenuButton
我完全沒提到是作什麼用。
在 GitHubTrendingApiClient
方法中有一個參數 since
,是這 API 可選填的參數之一。
那麼這邊就先很簡潔地用 PopupMenuButton
的方式作呈現
程式碼中,宣告 enum TrendingDateRange { daily, weekly, monthly }
,
在 AppBar.actions
中填入 PopupMenuButton
。
class TrendingPage extends StatefulWidget {
@override
_TrendingPageState createState() => _TrendingPageState();
}
class _TrendingPageState extends State<TrendingPage> {
TrendingDateRange _dateRange = TrendingDateRange.daily;
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: TabBar(...),
actions: <Widget>[
PopupMenuButton(
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<TrendingDateRange>(
child: Row(
children: <Widget>[
Icon(Icons.date_range),
SizedBox(width: 8.0),
Text("Date range"),
],
),
enabled: false,
),
CheckedPopupMenuItem<TrendingDateRange>(
value: TrendingDateRange.daily,
checked: _dateRange == TrendingDateRange.daily,
child: Text("daily"),
),
CheckedPopupMenuItem<TrendingDateRange>(
value: TrendingDateRange.weekly,
checked: _dateRange == TrendingDateRange.weekly,
child: const Text("weekly"),
),
CheckedPopupMenuItem<TrendingDateRange>(
value: TrendingDateRange.monthly,
checked: _dateRange == TrendingDateRange.monthly,
child: const Text("monthly"),
),
];
},
onSelected: (TrendingDateRange range) {
setState(() {
_dateRange = range;
});
},
),
],
),
body: TabBarView(
children: <Widget>[
TrendingProjects(dateRange: _dateRange),
TrendingDevelopers(dateRange: _dateRange),
],
),
),
);
}
}
將 TrendingPage
切換成 StatefulWidget
。
用 CheckedPopupMenuItem
讓每個選項前面有勾勾。
在 PopupMenuButton.onSelected
屬性裡使用 setState
來切換 _dateRange
。
TrendingProjects
與 TrendingDevelopers
新增屬性 dateRange
。
TrendingProjects
與 TrendingDevelopers
需作些微調。
主要注意紅框內的改變, initState 裡的東西轉移到 build 裡,這樣才能切換趨勢區間時,重新撈取資料與渲染頁面。
--
今日成果
好了,到今天本系列的第二部份 - API 串接篇進入第八天
差不多也要進入尾聲囉~