最近用Flutter重构了一下项目,第一次使用Flutter绘制首页的蒙版,把代码记录一下。
1.这个页面主要分为了三个大的图层,最底层就是我们的主页面的正常展示内容,中间一层是蒙版阴影和高亮部分,最上层是文字按钮区域。
2.蒙版阴影和白色高亮区域的绘制使用ColorFiltered,child使用stack,colorFilter里设置颜色半透明,模式为BlendMode.srcOut,看代码注释这个是显示源图像,但只显示两个图像不重叠的地方,这样就达到了重合的地方不显示,露出底层主页面的效果。
3.文字图形区域因为背景色是黑色的,所以不能将文字代码写在ColorFiltered的child里,如果写在里面的话,包括图形里的文字都会是透明的。
4.这里的高亮区域定位和文字按钮的图层定位可以通过底层页面的控件位置来确定。给控件设置key:GlobalKey(),使用key来获取控件位置和大小,然后通过位置和大小来给高亮区域设置left和top属性。
RenderBox box2 = Get.find<FirstLogic>()
.state
.messageKey
.currentContext
?.findRenderObject() as RenderBox;
state.secondSize =
Get.find<FirstLogic>().state.messageKey.currentContext?.size;
state.secondoffset = box2.localToGlobal(Offset.zero);
具体代码,这里代码是用GetX框架写的,所以有controller.state这个东西:
return Stack(
children: [
Container(
color: Colors.white,
child: Container(),
),
Visibility(
child: ColorFiltered(
colorFilter: const ColorFilter.mode(
Color(0xB3000000), BlendMode.srcOut),
child: Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.transparent,
)),
Positioned(
top: controller.state.firstoffset?.dy,
left: controller.state.firstoffset?.dx,
child: Container(
color: Colors.black,
height: controller.state.firstSize?.height,
width: controller.state.firstSize?.width,
)),
],
),
),
visible: true),
Visibility(child: Positioned(
child: Container(
color: Colors.transparent,
child: Stack(
children: [
Image.asset(R.mipmap.bg_meng),
Row(
children: [
Image.asset(R.mipmap.icon_blue_search),
Text(
'蒙版图片',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
).marginOnly(left: 13),
],
).marginOnly(top: 20, left: 11),
Positioned(
child: Row(
children: [
ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(20)),
clipBehavior: Clip.hardEdge,
child: TextButton(
onPressed: () => {},
child: Text(
'跳过',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
).paddingOnly(left: 16, right: 16),
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))),
backgroundColor: MaterialStateProperty.all(Colors.transparent),
overlayColor: MaterialStateProperty.all(Colors.transparent),
side: MaterialStateProperty.all(
BorderSide(color: Colors.white, width: 1),
),
alignment: Alignment.center,
textStyle: MaterialStateProperty.all(TextStyle(color: R.color.color_666666)),
),
),
),
ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(20)),
clipBehavior: Clip.hardEdge,
child: TextButton(
onPressed: () => {},
child: Text(
'知道了',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
).paddingOnly(left: 9, right: 9),
style: ButtonStyle(
//圆角弧度
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))),
//背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) {
return states.contains(MaterialState.pressed)
? R.color.color_0055c9
: R.color.THEME;
}),
overlayColor: MaterialStateProperty.all(Colors.transparent),
// overlayColor: MaterialStateProperty.resolveWith((states) {
// return states.contains(MaterialState.pressed) ? R.color.color_0055C9 : R.color.themeColor;}),
//设置按钮的大小
// minimumSize: MaterialStateProperty.all(Size(125,40)),
),
)).marginOnly(left: 11),
],
),
bottom: 4,
right: 17,
),
],
),
),
top: 20 +
((controller.state.firstoffset?.dy) ?? 0) +
((controller.state.firstSize?.height) ?? 0),
left: controller.state.firstoffset?.dx,
),visible: true),
],
);