flutter显示出底部控件的引导页

需求:同一个页面的两个不同的入口,同一个控件的位置有变化,显示引导页时对应这个控件的引导内容的位置也需要改变;同时半透明底部显示出真实的页面内容。

这样的需要如果切图然后再往页面上贴位置无法精确的对准。

思路:先绘制一层半透明遮罩覆盖页面,在需要显示的控件位置绘制为全透明,然后再将引导内容绘制在遮罩上面(共有三层,真实页面、透明遮罩。控件对应的那些说明内容),获取控件的位置确定在哪里全透明。

入口一进入时:

入口二进入时:

dart 复制代码
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});

  @override
  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);
  @override
  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);

  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false; // 不需要重绘,因为我们只是绘制一次,并没有动画或状态更改
  }
}
dart 复制代码
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);
  }
相关推荐
草履虫建模6 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq8 小时前
分布式系统安全通信
开发语言·c++·算法
Mr Xu_8 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠8 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
学嵌入式的小杨同学8 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
sleeppingfrog8 小时前
zebra通过zpl语言实现中文打印(二)
javascript
Re.不晚9 小时前
Java入门17——异常
java·开发语言
精彩极了吧9 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
南极星100510 小时前
蓝桥杯JAVA--启蒙之路(十)class版本 模块
java·开发语言
未来之窗软件服务10 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君