如何使用Flutter搭建一个薄荷APP
基础组件属性图解
1.1 Row
mainAxisAlignment(主轴对齐方式)
mainAxisAlignment用于控制主轴方向的子Widget的排列方式,默认的属性都是start。
MainAxisAlignment.start // 主轴顶部
MainAxisAlignment.end // 主轴底部对齐
MainAxisAlignment.center // 中间对齐
MainAxisAlignment.spaceBetween // 首尾组件贴边,中间的Widget平分空间
MainAxisAlignment.spaceAround // 中间平分空间,首尾Widget距离边的距离是它与中间的距离的一半
MainAxisAlignment.spaceEvenly // 完全平分
以薄荷我的页面,关注布局为例

- MainAxisAlignment.start(主轴顶部)

- MainAxisAlignment.end(主轴底部)

- MainAxisAlignment.center(中间对齐)

- MainAxisAlignment.spaceBetween(首尾组件贴边,中间的Widget平分空间)

- MainAxisAlignment.spaceAround(中间平分空间,首尾Widget距离边的距离是它与中间的距离的一半)

crossAxisAlignment(副轴对齐方式)
该属性的含义是次轴排列方式,根据上述构造函数可以知道Row和Column组件在次轴方向上默认都是居中。
crossAxisAlignment.start
crossAxisAlignment.end
crossAxisAlignment.center
crossAxisAlignment.stretch // 让子Widget填满次轴方向
crossAxisAlignment.baseline// 使得子Widget的baseline对齐
1.1.3 mainAxisSize
表示在主轴方向占用的空间,默认是MainAxisSize.max,表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row/Column的宽度始终等于主轴方向的最大宽度;
- MainAxisSize.min

- MainAxisSize.max

1.2 Container(容器组件)
Container是一个组合类容器,它是DecoratedBox、ConstrainedBox、Transform、Padding、Align等组件组合的一个多功能容器,所以我们只需通过一个Container组件可以实现同时需要装饰、变换、限制的场景:
Container({
this.alignment, // 内部widget对齐
this.padding, //容器内补白,属于decoration的装饰范围
Color color, // 背景色
Decoration decoration, // 背景装饰
Decoration foregroundDecoration, //前景装饰
double width,//容器的宽度
double height, //容器的高度
BoxConstraints constraints, //容器大小的限制条件
this.margin,//容器外补白,不属于decoration的装饰范围
this.transform, //变换
this.child,
})
1.3 Stack(层叠布局)
层叠布局和Web中的绝对定位、Android中的Frame布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。绝对定位允许子组件堆叠起来(按照代码中声明的顺序)。Flutter中使用Stack和Positioned这两个组件来配合实现绝对定位。Stack允许子组件堆叠,而Positioned用于根据Stack的四个角来确定子组件的位置。
首先先来看下默认的构造函数:
Stack({
this.alignment = AlignmentDirectional.topStart,// 此参数决定如何组件去对齐(没有使用Positioned)
this.fit = StackFit.loose,
this.overflow = Overflow.clip,
List<Widget> children = const <Widget>[],
})
fit:此参数用于确定没有定位的子组件如何去适应Stack的大小。StackFit.loose表示使用子组件的大小,StackFit.expand表示扩伸到Stack的大小。overflow:此属性决定如何显示超出Stack显示空间的子组件;值为Overflow.clip时,超出部分会被剪裁(隐藏),值为Overflow.visible 时则不会。
2. 利用Container+Row实现薄荷首页的搜索框
最终实现效果

组件拆解

代码实现
Container(
color: Color.fromARGB(_controller.value.alpha, 0, 205, 162),
padding: EdgeInsets.only( // 内边距
left: 17,
right: 17,
top: ScreenUtil.getStatusBarH(context) + 17,
bottom: 17),
child: Row( // 包含搜索图标和文字
children: <Widget>[
Expanded( // 为了让搜索框占满横向空间,除去购物车Icon、消息Icon
child: Container(
child: DecoratedBox( // 圆角和背景
decoration: BoxDecoration(
color: _controller.value.searchBarBg,
borderRadius: BorderRadius.circular(100),
),
child: Padding( // 上下边距,撑高内容
padding: EdgeInsets.only(top: 7, bottom: 7),
child: Row( // 左右排列搜索框和文字
children: <Widget>[
PaddingStyles.getPadding(14),
Image.asset(
Utils.getImgPath(_controller.value.appbarLeftIcon),
width: 24,
height: 24,
),
PaddingStyles.getPadding(7),
Text(
widget.text,
style: TextStyle(
fontSize: 14,
color: _controller.value.appbarTitleColor),
)
],
),
),
),
)),
Offstage(
child: SizeBoxFactory.getHorizontalSizeBox(14),
offstage: !widget.isShowCartIcon,
),
Offstage( // 购物车图标,Offstage是可以控制widget显示隐藏
offstage: !widget.isShowCartIcon,
child: Image.asset(
Utils.getImgPath("ic_shop_cart_white"),
width: 24,
height: 24,
),
),
SizeBoxFactory.getHorizontalSizeBox(14),
Image.asset(
Utils.getImgPath(_controller.value.appbarRightIcon),
width: 24,
height: 24,
)
],
),
)
最后可以通过封装成一个组件来实现其他页面的复用效果,具体代码如下:
/// 通用的搜索头部Widget
class SearchBar extends StatelessWidget {
final String text;
SearchBar(
{this.text});
@override
Widget build(BuildContext context) {
return Container(
.....
);
}
}
3. 复杂页面的拆解及实现(薄荷首页)

代码实现
Stack(
children: <Widget>[
CustomScrollView( // 统一滑动
controller: _controller, // 监听CustomScrollView滑动距离,搜索框颜色渐变
slivers: <Widget>[
SliverToBoxAdapter(
child: Stack(children: <Widget>[// 壁纸+减肥进度条
ExtendedImage.network( // 壁纸
wallImg,
height: 181,
width: double.infinity,
fit: BoxFit.fitWidth,
enableLoadState: false,
),
CardView( // 减肥进度条
margin: EdgeInsets.only(left: 17, right: 17, top: 104),
child: ....,
)
])),
SliverList( // 底部卡片ListView
......
......
),
],
),
SearchBar( // 顶部搜索框
text: "搜索食物和热量",
controller: _searchBarController,
key: _mTitleKey,
)
],
);
最后实现各部分组件对应的UI,首页就搭建出来了,源码在👇的GitHub链接
薄荷首页
