用 Flutter 轻松做个红包界面

语言: CN / TW / HK

theme: v-green highlight: atom-one-dark


本文正在参加「金石计划 . 瓜分6万现金大奖」

前言

在 Flutter 的开发中,最常见的就是层层的组件嵌套,因此不可避免会遇到子组件如何适配父组件的问题。比如,按钮的可点击区域是否要占满整个父组件?图片是居中还是居左?这些问题可以通过 Flutter 提供的FittedBox 组件来解决。

FittedBox 简介

FittedBox 组件设计的目的就是让其子组件与父级组件进行适配,包括对齐、缩放、裁剪和溢出处理。 dart const FittedBox({ Key? key, this.fit = BoxFit.contain, this.alignment = Alignment.center, this.clipBehavior = Clip.none, Widget? child, }) 如上所示,FittedBox 的定义很简洁,只有下面四个属性:

  • fit:子组件和父组件的适配模式,BoxFit 枚举,包括了不处理(none)、尽量包含(contain),拉伸填满(fill),宽度方向填满(fitWidth),高度方向填满(fitHeight)和缩小到父组件内(scaleDown),具体适配的样式可以看官方的文档 不同 BoxFit 样式
  • alignment:子组件与父组件的对齐方式,包括居中(center)、左侧居中(centerLeft)、右侧居中(centerRight),顶部居中(topCenter)、底部居中(bottomCenter)等。
  • clipBehavior:超出后的裁剪模式,即子组件溢出父组件后要不要裁剪,不裁剪的话子组件可能会超出父组件的显示范围。
  • child:要适配的子组件。

使用示例

我们来看一张图片在不同适配参数下的效果,这里我们可以在底部切换不同的适配模式,注意这里我们使用了裁剪来防止溢出,clipBehavior参数为 Clip.antiAlias。可以看到图片随着不同的模式显示的区域、对齐也会不同,这就给我们提供了子组件适配很大的灵活性。 fittedbox.gif 上面的示例代码如下。 dart var _fit = BoxFit.none; var _alignment = Alignment.center; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: const Text('FittedBox'), backgroundColor: Colors.red[400]!), body: Center( child: Container( width: MediaQuery.of(context).size.width - 30.0, height: 160.0, color: Colors.blue, child: FittedBox( alignment: _alignment, fit: _fit, clipBehavior: Clip.antiAlias, child: Image.asset('images/girl.jpeg'), ), ), ), bottomSheet: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ DropdownButton( items: const [ DropdownMenuItem<BoxFit>( value: BoxFit.none, child: Text('BoxFit.none'), ), DropdownMenuItem<BoxFit>( value: BoxFit.contain, child: Text('BoxFit.contain'), ), DropdownMenuItem<BoxFit>( value: BoxFit.fill, child: Text('BoxFit.fill'), ), DropdownMenuItem<BoxFit>( value: BoxFit.cover, child: Text('BoxFit.cover'), ), DropdownMenuItem<BoxFit>( value: BoxFit.fitHeight, child: Text('BoxFit.fitHeight'), ), DropdownMenuItem<BoxFit>( value: BoxFit.fitWidth, child: Text('BoxFit.fitWidth'), ), DropdownMenuItem<BoxFit>( value: BoxFit.scaleDown, child: Text('BoxFit.scaleDown'), ), ], value: _fit, onChanged: (fit) { setState(() { _fit = fit as BoxFit; }); }, ), DropdownButton( items: const [ DropdownMenuItem<Alignment>( value: Alignment.center, child: Text('Alignment.center'), ), DropdownMenuItem<Alignment>( value: Alignment.centerLeft, child: Text('Alignment.centerLeft'), ), DropdownMenuItem<Alignment>( value: Alignment.centerRight, child: Text('Alignment.centerRight'), ), DropdownMenuItem<Alignment>( value: Alignment.topCenter, child: Text('Alignment.topCenter'), ), DropdownMenuItem<Alignment>( value: Alignment.bottomCenter, child: Text('Alignment.bottomCenter'), ), DropdownMenuItem<Alignment>( value: Alignment.topLeft, child: Text('Alignment.topLeft'), ), ], value: _alignment, alignment: AlignmentDirectional.center, onChanged: (alignment) { setState(() { _alignment = alignment as Alignment; }); }, ), ], ), ); }

红包界面

下面我们来用 FittedBox 做一个红包界面效果,如下图所示。 image.png 这里红包顶部的深色部分其实就是用 FittedBox 将一个 Container 贴在了顶部居中位置。具体实现代码如下所示。 dart @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: const Text('FittedBox'), backgroundColor: Colors.red[400]!), body: Center( child: Stack( alignment: Alignment.center, children: [ Container( width: 240.0, height: 400.0, color: Colors.red, child: FittedBox( alignment: Alignment.topCenter, fit: BoxFit.fitWidth, clipBehavior: Clip.antiAlias, child: Container( height: 50.0, width: 160.0, decoration: BoxDecoration( borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(160.0), bottomRight: Radius.circular(160.0)), color: Colors.red[800], ), ), ), ), ClipOval( child: Container( width: 80, height: 80, alignment: Alignment.center, color: Colors.yellow[700], child: const Text( '開', style: TextStyle( fontSize: 42.0, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ), ), ], ), ), ); }

总结

本篇介绍了 Flutter 中的布局组件 FittedBox 的使用。FittedBox 是一个非常简单、但实用的组件,通过它,我们可以将子组件按一定的方式适配到父组件实现所需要的布局,从而简化开发中的布局样式的代码编写。


本篇源码已上传至:实用组件相关代码

我是岛上码农,微信公众号同名。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!

本文正在参加「金石计划 . 瓜分6万现金大奖」