结合上面的效果图,再结合下面的代码,大家应该一眼看出来,就知道是哪个widget方法,对应界面上的哪个控件;如果你想修改哪个控件样式,直接点进对应的widget方法里修改即可
children里面的每个widget方法上面,请一定一定记得写上注释,因为此处才是业务Widget最主要的入口,具体的widget方法写不写注释无所谓了
///搜索框 个人信息 设置等按钮 class HimalayaPersonalInfo extends StatelessWidget { HimalayaPersonalInfo({ Key key, this.onRefresh, this.onLeftArrow, this.onRightArrow, this.onSetting, this.onSkin, this.onChanged, }) : super(key: key); ............. @override Widget build(BuildContext context) { return _buildBg(children: [ //左图标 _buildLeftArrow(), //右图标 _buildRightArrow(), //刷新图标 _buildRefresh(), //搜索框 _buildSearch(), //头像 _buildHeadImg(), //皮肤 _buildSkin(), //设置 _buildSetting(), ]); } .......... }来看下其中的_buildBg方法
可以发现_buildBg主体的这些细节描述,真的是无关紧要的代码,这个写完后,基本上,后面都很少去改,所以把它提取出来后,放在墙角吃灰就行了
///搜索框 个人信息 设置等按钮 class HimalayaPersonalInfo extends StatelessWidget { ........ Widget _buildBg({List<Widget> children}) { return Container( margin: EdgeInsets.symmetric(vertical: 10.dp, horizontal: 18.dp), width: 800.dp, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: children, ), ); } }关于方法提取
选中你需要提取的Widget代码
打开 Flutter Outline 选择左箭头图片
填上方法命后,就能自动生成一个widget方法
如果你提取的Widget块中,还含有一些数据,自动生成的方法都会带上相应参数,非常方便
列表类样式封装类列表样式的封装也是比较关键的,直接从头莽尾式的提取是不行,这边有一丝调整
这里就以猜你喜欢模块举例
猜你喜欢模块
代码分析:总体是Column布局,分上下俩模块
上模块使用Row搞定即可
下模块是四个卡片,这边是直接用的写死List数据源
///猜你喜欢 class HimalayaGuess extends StatelessWidget { HimalayaGuess({ Key key, this.onChange, this.data, this.onGuess, }) : super(key: key); .......... @override Widget build(BuildContext context) { return _buildBg(children: [ //标题 + 换一批 Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ //标题 _buildTitle(), //换一批 _buildGuessChange() ]), //显示具体信息流 _buildItemBg(itemBuilder: (item) { return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ //图片卡片 _buildPicCard(item), //文字描述 Text(item.title, style: TextStyle(fontSize: 15.sp)), //作者 Text(item.subTitle, style: TextStyle(fontSize: 13.sp, color: Colors.grey)), ]); }) ]); } .......... }上述children代码,整体上还是比较清晰,有点迷糊的,可能就是_buildItemBg,来看看其中代码
此方法对面暴露了一个itemBuilder参数,这其实是一个回调方法
因为列表类样式,必须要遍历整个列表数据,然后,需要把列表遍历的具体数据,反向传给Widget,所以必须使用此类的回调方法
///猜你喜欢 typedef HimalayaSubBuilder = Widget Function(HimalayaSubItemInfo item); class HimalayaGuess extends StatelessWidget { ............... Widget _buildItemBg({HimalayaSubBuilder itemBuilder}) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: data.map((e) { return itemBuilder(e); }).toList(), ); } }关于双层列表数据源(List的每个具体数据源,又含有List)又该怎么封装呢?
俩层List数据源封装是比较麻烦,这边以侧边栏举例
整个布局是一个Column:标题 + 栏目(List数据控制)
栏目:可划分具体的Item
Item:标题 + 栏目(List数据控制)
代码实现
上面的布局整体是由数据源驱动页面,数据能控制页面item生成
///数据源:侧边导航栏目初始数据,简化了下,数据源太长了 ///该数据源都放在state层维护,此处放在这里,让大家有个对比 leftItemList = [ HimalayaItemInfo(title: '推荐', subItemList: [ HimalayaSubItemInfo( title: '发现', icon: CupertinoIcons.compass, tag: TagHimalayaConfig.find, isSelected: true, ).obs, .............. ]), HimalayaItemInfo(title: '我听', subItemList: [ HimalayaSubItemInfo( title: '我的订阅', icon: Icons.star_border, tag: TagHimalayaConfig.subscription, ).obs, ......... ]), HimalayaItemInfo(title: '我创建的听单', subItemList: [ HimalayaSubItemInfo( title: '我喜欢的声音', icon: Icons.favorite_border, tag: TagHimalayaConfig.sound, ).obs, ............ ]), ]; ///左边导航栏 class HimalayaLeftNavigation extends StatelessWidget { HimalayaLeftNavigation({ Key key, this.data, this.onTap, }) : super(key: key); ........ @override Widget build(BuildContext context) { return _buildBg(children: [ //喜马拉雅logo图标 _buildLogo(), //遍历俩层循环:不同item栏目 - 可点击,可滑动 //第一层:标题 + 子item列表 //第二层:子item详细布局 _buildItemListBg(itemBuilder: (item) { return [ //最外层item - 大标题 _buildTitle(item.title), //子栏目 - 列表 _buildSubItemListBg( data: item, subBuilder: (subItem) => _buildSubItemBg(data: subItem, children: [ //选中红色长方形条块 _buildRedTag(subItem), //图标 _buildItemIcon(subItem), //描述 _buildItemDesc(subItem), ]), ), ]; }), ]); } .......... }第一层:来看下第一层_buildItemListBg方法