从 Flutter 2.0 开始学 - 构建关注展示界面
关注界面效果 |
---|
在 Flutter 中一切皆 Widget,再大的界面,都可以划分成一个一个小的组件,拼成一个大的组件。
根据数据渲染,每个小的组件可以负责不同的业务逻辑。
组件划分
编码
ATHFollowContent
import 'follow_item.dart';
class ATHFollowContent extends StatefulWidget {
@override
_ATHFollowContentState createState() => _ATHFollowContentState();
}
class _ATHFollowContentState extends State<ATHFollowContent>
with AutomaticKeepAliveClientMixin {
// 总数
@override
Widget build(BuildContext context) {
super.build(context);
List<ATHFollowItemModel> followItemList = MockFollowItemData.followItemList;
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
ATHFollowItemModel followItem = followItemList[index];
return ATHFollowItem(
followItem: followItem,
);
},
childCount: followItemList.length,
),
),);
}
@override
bool get wantKeepAlive => true;
}
-
AutomaticKeepAliveClientMixin 接口,使用当前组件保持状态 -
实现 bool get wantKeepAlive => true; 函数 -
通过 ATHFollowItem 创建,构建每一条 Item
ATHFollowItem
class ATHFollowItem extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowItem({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ATHFollowUserInfo(followItem: followItem),
ATHFollowContent(followItem: followItem),
followItem.images.length > 0
? ATHFollowGridImage(followItem: followItem)
: SizedBox(),
ATHFollowComment(followItem: followItem),
ATHFollowOperation(followItem: followItem),
Padding(
padding: EdgeInsets.symmetric(vertical: kSize20),
child: ATHItemDivider(),
),
],
),
);
}
}
ATHFollowUserInfo
-
显示用户头像,介绍信息
class ATHFollowUserInfo extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowUserInfo({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: ATHUserAvatar(
avatarPath: followItem.poetryItem.poetryAvatar,
),
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: kSize24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(
followItem.poetryItem.poetryAuthor ?? "",
style: TextStyle(color: kColor33, fontSize: kSize30),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
followItem.createTime ?? "",
style: TextStyle(color: kColor33),
),
],
)
],
),
),
)
],
);
}
}
ATHFollowContent
-
显示内容
class ATHFollowContent extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowContent({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: kSize20),
child: Text(
followItem.poetryItem.poetryTitle ?? "",
style: TextStyle(fontSize: kSize32),
),
),
Text(followItem.poetryItem.poetryContent ?? "",
style: TextStyle(color: kColor66, fontSize: kSize32))
],
);
}
}
ATHFollowGridImage
-
显示图片,多张图片,为一个 GridView
class ATHFollowGridImage extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowGridImage({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
List<String> imageList = followItem.images;
return GridView.custom(
shrinkWrap: true,
padding: EdgeInsets.only(top: kSize20),
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: kSize20,
crossAxisSpacing: kSize20,
),
childrenDelegate: SliverChildBuilderDelegate((context, position) {
String imagePath = imageList[position];
return Container(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(kSize8)),
child: Image.asset(
imagePath,
fit: BoxFit.cover,
),
),
);
}, childCount: imageList.length),
);
}
}
ATHFollowComment
-
评论组件
class ATHFollowComment extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowComment({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: EdgeInsets.only(top: kSize20),
padding: EdgeInsets.all(kSize16),
decoration: BoxDecoration(
color: kColorF1F1F1,
borderRadius: BorderRadius.all(Radius.circular(kSize8))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/icons/icon_hot.svg', width: kSize30),
Text(
101 >= 100 ? "热评" : "",
style: TextStyle(color: kColor33, fontSize: kSize22),
)
],
),
Text(
"${followItem.commentItem.commentLike}赞",
style: TextStyle(color: kColor33),
)
],
),
Padding(
padding: EdgeInsets.only(top: kSize8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
followItem.commentItem.commentAuthor + " : " ?? "",
style: TextStyle(color: kPrimaryColor),
),
Text(
followItem.commentItem.commentContent ?? "",
style: TextStyle(color: kColor33),
),
],
),
Text(
followItem.commentItem.commentTime ?? "",
style: TextStyle(color: kColor33, fontSize: kSize24),
),
],
),
)
],
),
);
}
}
ATHFollowOperation
-
可以操作按钮,显示分享、评论、点赞...
class ATHFollowOperation extends StatelessWidget {
final ATHFollowItemModel followItem;
const ATHFollowOperation({Key key, this.followItem}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: kSize20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding:
EdgeInsets.symmetric(horizontal: kSize10, vertical: kSize4),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(kSize8)),
shape: BoxShape.rectangle,
color: kColorF1F1F1),
child: Text(
followItem.tag ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: kSize24, color: kColor99),
)),
Padding(
padding: EdgeInsets.only(top: kSize16),
child: ATHOperatorView(),
),
],
),
);
}
}
构建模拟数据
-
由数据驱动,界面展示根据数据
class MockFollowItemData {
static List<ATHFollowItemModel> followItemList = [
ATHFollowItemModel(
poetryItem: ATHPoetryItemModel(
poetryAuthor: "杜甫-少陵野老",
poetryTitle: "登高",
poetryAvatar: "assets/images/dufu.jpg",
poetryContent:
"风急天高猿啸哀,渚清沙白鸟飞回。\n无边落木萧萧下,不尽长江滚滚来。\n万里悲秋常作客,百年多病独登台。\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。",
),
images: [
'assets/images/qrcode_430.jpg',
'assets/images/qrcode_430.jpg',
'assets/images/qrcode_430.jpg',
],
commentItem: ATHCommentItemModel(
commentAuthor: "江景",
commentAuthorAvatar: "assets/images/libai.jpg",
commentContent: "哈哈哈,可以可以。",
commentLike: 831,
commentTime: "752-02-23 23:23:23"),
createTime: "752-02-22 22:22:22",
tag: "萧瑟荒凉之感",
likeCount: 678,
),
ATHFollowItemModel(
poetryItem: ATHPoetryItemModel(
poetryAuthor: "李白-诗仙",
poetryTitle: "三五七言 / 秋风词",
poetryAvatar: "assets/images/libai.jpg",
poetryContent:
"秋风清,秋月明,\n落叶聚还散,寒鸦栖复惊。\n相思相见知何日?此时此夜难为情!\n入我相思门,知我相思苦,\n长相思兮长相忆,短相思兮无穷极,\n早知如此绊人心,何如当初莫相识。",
),
images: [
'assets/images/qrcode_430.jpg',
],
commentItem: ATHCommentItemModel(
commentAuthor: "杜甫-少陵野老",
commentAuthorAvatar: "assets/images/libai.jpg",
commentContent: "emm,有点意思",
commentLike: 9831,
commentTime: "752-10-23 02:00:13"),
createTime: "752-10-23 01:00:13",
tag: "高悬天空明月",
likeCount: 1678,
),
];
}
添加到 home 到 tabContents
TabBarView _buildTabBarView() {
List<Widget> tabContents = [];
for (int index = 0; index < _tabsText.length; index++) {
if (index == 0) {
// 添加这个
tabContents.add(ATHFollowContent());
} else if (index == 1) {
tabContents.add(ATHRecommendContent());
} else {
tabContents.add(Center(child: Text(_tabsText[index])));
}
}
return TabBarView(controller: _tabController, children: tabContents);
}
-
完成这一步可以编译构建看效果啦 ~