Flutter 实战:撸半个知乎日报~ThemeListPage
2018-06-23 本文已影响316人
jzhu085
fir_release_Android包下载地址
GIF
themelist.gifUI如图
themelisgpage.png需求分析:
- 整体滑动
- 背景,标题,顶部导航栏联动,渐隐渐出动画
- 装载数据
UI拆解并实现:
-
CustomScrollView: 负责整体滑动
var content = new CustomScrollView(
//没有铺满也可以滑动
physics: AlwaysScrollableScrollPhysics(),
........
........
)
-
SliverAppBar:背景,标题,顶部导航栏联动,渐隐渐出动画
new SliverAppBar(
expandedHeight: _appBarHeight,
pinned: _appBarBehavior == AppBarBehavior.pinned,
floating: _appBarBehavior == AppBarBehavior.floating ||
_appBarBehavior == AppBarBehavior.snapping,
snap: _appBarBehavior == AppBarBehavior.snapping,
flexibleSpace: new FlexibleSpaceBar(
//标题
title: Text('$_title'),
//背景图
background: new FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: _barBg,
fit: BoxFit.fitHeight),
),
)
-
SliverList:
拆解1:主编一栏
Widget _buildEditor() {
//横向控件的集合
List<Widget> editors = [];
//主编
Widget lableWidget = new Padding(
padding: const EdgeInsets.only(right: 12.0),
child: new Text(
'主编',
style: new TextStyle(fontSize: 14.0),
),
);
editors.add(lableWidget);
//循环加入主编的头像
for (ThemeListEditorsModel model in _editorDatas) {
Widget headView = new InkWell(
onTap: () {
RouteUtil.route2Web(context, model.name, model.url);
},
child: new Padding(
padding: const EdgeInsets.only(
left: 6.0, right: 6.0, top: 12.0, bottom: 12.0),
child: new CircleAvatar(
radius: 12.0,
backgroundImage: new NetworkImage(model.avatar),
)),
);
editors.add(headView);
}
//组装
return new Column(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new Row(
children: editors,
),
),
CommonDivider.buildDivider(),
],
);
}
拆解2:基础item
Widget _buildNormalItem(ThemeListStoriesModel item) {
final List images = item.images;
final String title = item.title;
final int id = item.id;
bool hasImage = (null != images && images.isNotEmpty);
if (hasImage) {
return new InkWell(
onTap: () {
RouteUtil.route2Detail(context, '$id');
},
child: new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: new Text(
title,
style: new TextStyle(
fontSize: 16.0, fontWeight: FontWeight.w300),
),
),
new Padding(
padding: const EdgeInsets.all(8.0),
child: new SizedBox(
height: 80.0,
width: 80.0,
child: new Image.network(images[0]),
),
)
],
),
new Expanded(
child: new Align(
alignment: Alignment.bottomCenter,
child: CommonDivider.buildDivider(),
),
),
],
),
)));
} else {
return new InkWell(
onTap: () {
RouteUtil.route2Detail(context, '$id');
},
child: new Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Expanded(
child: new SizedBox(
height: Constant.normalItemHeight,
child: new Align(
alignment: Alignment.centerLeft,
child: new Text(
title,
style: new TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w300),
),
),
),
),
],
),
new Expanded(
child: new Align(
alignment: Alignment.bottomCenter,
child: CommonDivider.buildDivider(),
),
),
],
),
)));
}
}
拆解3:根据类型显示item
Widget _buildNewItem(ThemeListStoriesModel item) {
Widget widget;
switch (item.itemType) {
case ThemeListStoriesModel.itemTypeEditor:
widget = _buildEditor();
break;
case ThemeListStoriesModel.itemTypeNormal:
widget = _buildNormalItem(item);
break;
}
return widget;
}
拆解4:组装
new SliverList(
delegate: new SliverChildListDelegate(
new List<Widget>.generate(_normalDatas.length, (int i) {
return _buildNewItem(_normalDatas[i]);
})),
),
拆解5:刷新
var _refreshIndicator = new NotificationListener(
onNotification: _onNotification,
child: new RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _refreshData,
child: content,
),
);
拆解6:加载更多
void _scrollListener() {
//滑到最底部刷新
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadData();
}
}