需求:同一个页面的两个不同的入口,同一个控件的位置有变化,显示引导页时对应这个控件的引导内容的位置也需要改变;同时半透明底部显示出真实的页面内容。
这样的需要如果切图然后再往页面上贴位置无法精确的对准。
思路:先绘制一层半透明遮罩覆盖页面,在需要显示的控件位置绘制为全透明,然后再将引导内容绘制在遮罩上面(共有三层,真实页面、透明遮罩。控件对应的那些说明内容),获取控件的位置确定在哪里全透明。
import 'package:common/sp_util.dart';
import 'package:jade/configs/CommonConfig.dart';
import 'package:jade/configs/PathConfig.dart';
import 'package:jade/utils/JadeColors.dart';
import 'package/jade/utils/Utils.dart';
import 'package:util/navigator_util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/*
* 引导页
* */
class SharedPurchaseGuidePage extends StatelessWidget {
final double width;
final double height;
final Offset offset;
const SharedPurchaseGuidePage({this.width,this.height,this.offset});
Widget build(BuildContext context) {
return WillPopScope(
child: Stack(
children: [
CustomPaint(
size: Size(Utils().screenWidth(context), Utils().screenHeight(context)), // 自定义Widget的大小
painter: MyCustomPainter(width,height,offset),
),
Positioned(
left: offset.dx + width,
top: offset.dy,
child: _leftView(context))
],
),
onWillPop: () async => false,);
}
_leftView(context){
return Container(
width: Utils().screenWidth(context) * 0.68,
height: 210.w,
padding: EdgeInsets.symmetric(vertical: 28.w),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(PathConfig.imageSharedPurchaseGuideBg),
fit: BoxFit.fill)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text('点击了解共享购',style: TextStyle(color: Colors.white,fontSize: 28.sp,fontWeight: FontWeight.w600)),
SizedBox(width: 54.w),
GestureDetector(
child: Container(
width: 100.w,
height: 40.w,
alignment: Alignment.center,
margin: EdgeInsets.only(right: 20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Text('知道了',style: TextStyle(color: JadeColors.blue,fontSize: 22.sp,fontWeight: FontWeight.w600),),
),
onTap: (){
SpUtil.putBool(CommonConfig.havePostDetailSharedPurchaseGuide, true);
NavigatorUtil.pop();
},
)
],
),
Container(
margin: EdgeInsets.only(right: 20.w,top: 26.w),
child: Text('为促进交易,本版块加入了独特的共\n享购功能,与传统的团购与拼单很不\n一样,欢迎体验!',style: TextStyle(color: Colors.white,fontSize: 22.sp))
)
],
),
);
}
}
class MyCustomPainter extends CustomPainter {
final double width;
final double height;
final Offset offset;
const MyCustomPainter(this.width,this.height,this.offset);
void paint(Canvas canvas, Size size) {
//背景
Paint backgroundPaint = Paint()
..color = Colors.black45
..style = PaintingStyle.fill;
//添加背景一个路径
Path path = Path()
..addRect(Rect.fromLTWH(0, 0, size.width, size.height));
//留白的圆角矩形路径
Path holePath = Path()
// ..addRect(Rect.fromLTWH(offset.dx, offset.dy, width, height));
..addRRect(RRect.fromRectAndRadius(Rect.fromLTWH(offset.dx-5, offset.dy, width+5, height), Radius.circular(5)));
Path combinedPath = Path.combine(PathOperation.difference, path, holePath);
canvas.drawPath(combinedPath, backgroundPaint);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false; // 不需要重绘,因为我们只是绘制一次,并没有动画或状态更改
}
}
GlobalKey _sharedPurchaseKey = new GlobalKey();
//需要全透明的控件
Row(
key: _sharedPurchaseKey,
children: [
Text(S.current.sharedPurchase,style: TextStyle(color: JadeColors.blue,fontSize: 24.sp,fontWeight: FontWeight.bold)),
GestureDetector(
child: Container(
color: Colors.transparent,
padding: EdgeInsets.all(4),
child: Image.asset(PathConfig.iconQuestion,width: 34.w,height: 34.w),
),
onTap: (){
NavigatorUtil.push(SharedPurchaseDesc());
},
),
],
),
//获取共享购文字加问号的坐标,跳转(这个方法需要在页面加载完成后调用)
_getOffset() {
if(_sharedPurchaseKey.currentContext != null){
_sharedPurchaseWidth = _sharedPurchaseKey.currentContext.size.width;
_sharedPurchaseHeight = _sharedPurchaseKey.currentContext.size.height;
_offset = WidgetUtil.getWidgetLocalToGlobal(_sharedPurchaseKey.currentContext);
bool sharedPurchaseGuide = SpUtil.getBool(CommonConfig.havePostDetailSharedPurchaseGuide,defValue: false);
if(!sharedPurchaseGuide){
//跳转一个透明页面
NavigatorUtil.pushTransparentRoute(SharedPurchaseGuidePage(width: _sharedPurchaseWidth,height: _sharedPurchaseHeight,offset: _offset));
}
}
}
///Get the coordinates of the widget on the screen.Widgets must be rendered completely.
///获取widget在屏幕上的坐标,widget必须渲染完成
static Offset getWidgetLocalToGlobal(BuildContext context) {
RenderBox box = context.findRenderObject();
return box == null ? Offset.zero : box.localToGlobal(Offset.zero);
}