携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情 >>
状态组件
由于无状态组件在执行过程中只有一个build阶段
在执行期间只会执行一个build函数,没有其他生命周期函数
因此在执行速度和效率方面比有状态组件更好
所以在设计组件时,不要任何组件都使用有状态组件进行开发,要根据实际分析情况使用
Text:文本显示组件,里面包含了文本类相关的样式以及排版相关的配置信息
Image:图片显示组件,里面包含了图片的来源设置,以及图片的配置
Icon: Icon库,里面是Flutter原生支持的一些小的icon FlatButton :包含点击动作的组件
Row:布局组件,在水平方向上依次排列组件
Column:布局组件,在垂直方向上依次排列组件
Container:布局组件,容器组件,这点有点类似于前端中的body
Expanded :可以按比例“伸” Row, Column 和Flex 子组件所占用的Padding :可填充空白区域组件,这点和前端的padding功能基本一致ClipRRect:圆角组件,可以让子组件有圆形边角
由于动态组件和静态组件的特点,因此在组合的时候要非常注意,动态组件下的子组件如果过多。
则在组件更新的时候,会导致其子组件的全部更新,从而引发性能问题
- 尽可能减少动态组件下的静态组件
- 数据来源相同的部分组合为同一组件
- 使用行或者列作为合并的条件
- 功能相同的部分,转化为基础组件
- 合并后根节点的为Container
快速模仿一个掘金界面
设计方案
将设计方案分为以下几个过程
1.标记所有界面元素(Flutter基础组件),按照数字进行标记,请注意明显相似部分不需要标记
2.记录相应数字对应的组件名称,并命名展示数据的参数名
3.标记需要交互和数据变化的数据
4.将数字和数据合成一个最小组件,并标记组件是有或无状态组件
5.将第4步中的最小组件进行合并,组件组合规则,请参照上面介绍到的“组件组合要点”
6.完成组件合并后,绘制一张组件图,再次分析动态组件下的静态组件是否合理,如果能拆分尽量拆分
第一步:标记界面元素
将UI或原型的界面元素标记出来,方便我们后面快速设计
第二步:记录组件名称以及组件数据,标记动态数据
| 编号 | 基础组件 | 组件作用 | 组件数据 | 是否动态 |
|---|---|---|---|---|
| 1 | Text | 文章作者 | nickName | 否 |
| 2 | Text | 发布日期 | date | 否 |
| 3 | Text | 分类 | category | 否 |
| 4 | CloseButton | 移除文章 | / | 否 |
| 6 | Text | 文章标题 | title | 否 |
| 7 | Text | 描述预览 | summary | 否 |
| 8 | Image | 文章配图 | image | 否 |
| 9 | IconButton | 浏览数 | browseNum | 否 |
| 10 | IconButton | 点赞数 | likeNum | 是 |
| 10 | IconButton | 评论数 | comNum | 是 |
第三步:组件合并
使用画图的方式比较直观一点,我用的 ProcessOn 工具
项目文件结构实例
根据表格创建相应的目录结构和组件对象,后面的编码过程会相对的简单。
最终效果
练习代码
# home_page.dart
import 'package:flutter/material.dart';
import 'package:f_element/LElement/util.struct/article_summary_struct.dart';
import 'package:f_element/LElement/util.struct/user_info_struct.dart';
import 'package:f_element/LElement/widgets/home_page/article_card.dart';
class HomePage extends StatelessWidget {
//广告 banner 信息
final String bannerImage = 'http://5b0988e595225.cdn.sohucs.com/images/20190525/dba69c9a62894ccbb994ded678e5c969.jpeg';
//用户基本信息
final UserInfoStruct userInfo = UserInfoStruct(nickname: 'Flutter代码君:', headerIcon: 'https://c-ssl.dtstatic.com/uploads/avatar/202201/01/20220101083802_66eda.thumb.100_100_c.jpeg', commentNum: 221);
//文章基本信息
final ArticleSummaryStruct articleInfo = ArticleSummaryStruct(
title:'淘宝iOS扫一扫架构升级 - 设计模式的应用' ,
summary:'本文在“扫一扫功能的不断迭代,基于设计模式的基本原则,逐步采用设计模式思想进行代码和架构优化”的背景下,对设计模式在扫一扫中新的应用进行了总结。',
articleImage:'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2c73fb8487694dafaccfca73e1e06bed~tplv-k3u1fbpfcp-zoom-crop-mark:3024:3024:3024:1702.awebp?',
postDate: '2022年08月21日',
category: 'Flutter',
comNum: 42,
browseNum: 5221,
likeNum:122);
@override
Widget build(BuildContext context) {
// TODO: implement build
return ArticleCard(userInfo: userInfo, articleInfo: articleInfo);
}
}
# article_summary_struct.dart
/*
* 文章信息数据结构
* */
class ArticleSummaryStruct {
String? title;//文章标题
String? summary;//描述预览
String? articleImage;//文章配图
String? postDate;//文章发表日期
String? category;//文章分类
int? likeNum;//点赞数
int? comNum;//评论数
int? browseNum;//浏览数
ArticleSummaryStruct({this.title, this.summary,this.articleImage,this.likeNum,this.comNum,this.browseNum,this.postDate,this.category});
}
# user_info_struct.dart
//用户信息
class UserInfoStruct {
String? nickname;
String? headerIcon;
int? commentNum;
UserInfoStruct({this.nickname, this.headerIcon, this.commentNum});
}
# article_bottom_bar.dart
import 'package:flutter/material.dart';
class ArticleBottomBar extends StatefulWidget {
int? likeNum;//点赞数
int? comNum;//评论数
int? browseNum;//浏览数
ArticleBottomBar({Key? key,this.likeNum,this.comNum,this.browseNum}):super(key: key);
@override
State<ArticleBottomBar> createState() => _ArticleBottomBarState();
}
class _ArticleBottomBarState extends State<ArticleBottomBar> {
int likeNum = 0;//点赞数
int comNum = 0;//评论数
int browseNum = 0;//浏览数
void taplike(){
setState(() {
print("点赞+1,$likeNum");
likeNum = likeNum+1;
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
likeNum = widget.likeNum!;
comNum = widget.comNum!;
browseNum = widget.browseNum!;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(
children: [
IconButton(onPressed: null, icon: Icon(Icons.ad_units_rounded)),
Text('浏览数:$browseNum'),
IconButton(onPressed:()=>taplike(), icon: Icon(Icons.thumb_up_off_alt)),
Text("点赞数:$likeNum"),
IconButton(onPressed: null, icon: Icon(Icons.comment_outlined)),
Text("评论数:$comNum"),
],
);
}
}
# article_card.dart
import 'package:flutter/material.dart';
//数据结构
import 'package:f_element/LElement/util.struct/article_summary_struct.dart';
import 'package:f_element/LElement/util.struct/user_info_struct.dart';
//一级组件
import 'package:f_element/LElement/widgets/home_page/article_bottom_bar.dart';
import 'package:f_element/LElement/widgets/home_page/article_summary.dart';
import 'package:f_element/LElement/widgets/home_page/article_top_bar.dart';
// ArticleCard 属于静态组件只需要继承 StatelessWidget 即可
class ArticleCard extends StatelessWidget {
//用户信息
final UserInfoStruct userInfo;
//帖子信息
final ArticleSummaryStruct articleInfo;
//构造函数
const ArticleCard({Key? key, required this.userInfo, required this.articleInfo}):super(key: key);
//创建组件
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: [
ArticleTopBar(nickName: userInfo.nickname,date: articleInfo.postDate,category: articleInfo.category),
ArticleSummary(title: articleInfo.title,summary: articleInfo.summary,articleImage: articleInfo.articleImage),
ArticleBottomBar(likeNum: articleInfo.likeNum,browseNum: articleInfo.browseNum,comNum: articleInfo.comNum)
],
);
}
}
# article_summary.dart
import 'package:flutter/material.dart';
class ArticleSummary extends StatelessWidget {
final String? title;
final String? summary;
final String? articleImage;
const ArticleSummary({Key? key, this.title, this.summary, this.articleImage}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(children: [
Column(children: [
SizedBox(width: 250,child: Text(title!, overflow: TextOverflow.clip, style: TextStyle(color: Colors.blue,fontWeight: FontWeight.bold),),),
SizedBox(width: 230,child: Text(summary!, overflow: TextOverflow.clip),),
]
),
Image.network(articleImage!, height: 70)
// Text(title!,overflow: TextOverflow.ellipsis),
]);
}
}
# article_top_bar.dart
import 'package:flutter/material.dart';
//文章顶部信息
class ArticleTopBar extends StatelessWidget {
final String? nickName;//文章作者
final String? date;//发表日期
final String? category;//分类
const ArticleTopBar({Key? key,this.nickName,this.date,this.category}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(
children: [
Text(nickName!),
Text(date!),
Text(category!),
const CloseButton(color: Colors.black, onPressed: null)
]
);
}
}