无法找到带有第三方库的文本小部件

问题描述

我正在为使用CoachMark库(https://pub.dev/packages/tutorial_coach_mark)的应用程序使用Flutter驱动程序编写集成测试

我想单击文本以关闭CoachMark,但是当我尝试使用VSCode的窗口小部件检查器对其进行检查时,文本没有显示在窗口小部件树上,当我将检查器悬停在该文本上时,它指向MaterialApp根小部件(请参见屏幕截图)

what i want to click is a text with OKE text

这些是我尝试找不到运气的方法:

  1. find.byType('Text')
  2. find.text('OKE')
  3. find.byType('RichText')
  4. 甚至是这个嵌套的,令人困惑的发现者

return find.descendant(of: find.byType('Align'),matching: find.descendant(of:find.byType('SafeArea'),matching: find.descendant(of:find.byType('AnimatedOpacity'),matching: find.descendant(of:find.byType('InkWell'),matching: find.descendant(of: find.byType('Padding'),matching: find.text('OKE'))))));

我尝试使用第4种方法的原因是当我尝试深入研究库代码本​​身时,它会构建类似这样的小部件

  Widget _buildSkip() {
    if (widget.hideSkip) {
      return SizedBox.shrink();
    }
    return Align(
      alignment: widget.alignSkip,child: SafeArea(
        child: AnimatedOpacity(
          opacity: showContent ? 1 : 0,duration: Duration(milliseconds: 300),child: InkWell(
            onTap: widget.clickSkip,child: Padding(
              padding: const EdgeInsets.all(20.0),child: Text(
                widget.textSkip,style: widget.textStyleSkip
              ),),);
  }

我附加了一个屏幕截图,以显示我要单击的内容(屏幕右下角的文字)

enter image description here

有什么建议吗?

修改
这是主屏幕:

class HomeSearchBarWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BaseWidget<HomeSearchBarViewModel>(
      model: HomeSearchBarViewModel(
        Provider.of<TrackingService>(context),Provider.of<ErrorReportingService>(context),onModelReady: (model) => model.initModel(),builder: (context,model,child) {
        return Container(
          padding: EdgeInsets.only(bottom: 5.0),margin: EdgeInsets.only(top: 8,left: 16,right: 8),alignment: Alignment.centerLeft,width: MediaQuery.of(context).size.width,child: Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                  ImageHelper.logo,UIHelper.horzSpace(16),Expanded(
                    child: TextFormField(
                      readOnly: true,decoration: new InputDecoration(
                        contentPadding: EdgeInsets.all(14),labelStyle: PinTextStyles.styleBody2(
                          PinColorsV2.neutral500,prefixIcon: Icon(
                          Icons.search,color: PinColorsV2.neutral500,border: UIHelper.inputBorder,hintText: "Lokasi atau nama proyek",hintStyle: PinTextStyles.styleBody2(
                          PinColorsV2.neutral200,enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(
                            color: PinColorsV2.neutral200,focusedBorder: OutlineInputBorder(
                          borderSide: BorderSide(
                            color: PinColorsV2.neutral200,onTap: () async {
                        await model.trackLogEvent(
                          HomeSearchBarTrackingKeys.clickSearch,);
                        Navigator.pushNamed(
                          context,RoutePaths.ProjectSearch,arguments: {
                            "keyword": "",},);
                      },UIHelper.horzSpace(12),CoachMarkWidget(
                    targets: model.targets,keyTarget: model.helpCenterKey,targetIdentify: "Help-Center",title: "Punya pertanyaan terkait penggunaan aplikasi?",description:
                    "Temukan semua solusinya dengan tap ikon tanda tanya di sudut kanan atas.",onFinish: () => model.hideCoachMark(),isVisible: model.coachMark != null && model.coachMark.value,focusWidget: HelpCenterIconWidget(
                      page: HelpCenterPage.homePage,iconColor: PinColorsV2.neutral500,screenNameFrom: HomeViewTrackingKeys.open,],);
      },);
  }
}

class HomeSearchBarTrackingKeys {
  static const String clickSearch = "landing_click_search";
}


class CoachMarkWidget extends StatelessWidget {
  final List<TargetFocus> targets;
  final GlobalKey keyTarget;
  final String targetIdentify;
  final String title;
  final String description;
  final bool isVisible;
  final Function() onFinish;
  final Widget focusWidget;

  CoachMarkWidget({
    this.targets,this.keyTarget,this.targetIdentify,this.title,this.description,this.isVisible = true,this.onFinish,this.focusWidget,});

  void initTargetCoachMark() {
    return targets.add(
      TargetFocus(
        identify: targetIdentify,keyTarget: keyTarget,contents: [
          ContentTarget(
            align: AlignContent.bottom,child: Container(
              padding: EdgeInsets.symmetric(
                horizontal: 48,child: Column(
                children: <Widget>[
                  Text(
                    title,style: PinTextStylesV2.styleHeadingXSmall(
                      color: PinColorsV2.neutralWhite,).merge(
                      TextStyle(
                        height: 1.22,Padding(
                    padding: EdgeInsets.only(top: 8),child: Text(
                      description,style: PinTextStylesV2.styleParagraphLarge(
                        color: PinColorsV2.neutralWhite,).merge(
                        TextStyle(
                          height: 1.5,);
  }

  showTutorial(
    BuildContext context,) {
    return TutorialCoachMark(
      context,targets: targets,colorShadow: PinColorsV2.blue300,opacityShadow: 0.85,textSkip: "OKE",widgetKey: Key('OKE'),// key: Key("oke"),textStyleSkip: PinTextStylesV2.styleActionMedium(
        color: PinColorsV2.neutralWhite,onFinish: () async {
        await onFinish();
      },onClickTarget: (target) async {
        await onFinish();
      },onClickSkip: () async {
        await onFinish();
      },)..show();
  }

  @override
  Widget build(BuildContext context) {
    initTargetCoachMark();
    if (isVisible) {
      WidgetsBinding.instance.addPostFrameCallback(
        (_) {
          showTutorial(context);
        },);
    }
    return Container(
      key: keyTarget,child: focusWidget,);
  }
}

这是自定义小部件代码
class TutorialCoachMark{
  final BuildContext _context;
  final List<TargetFocus> targets;
  final Function(TargetFocus) onClickTarget;
  final Function() onFinish;
  final double paddingFocus;
  final Function() onClickSkip;
  final AlignmentGeometry alignSkip;
  final String textSkip;
  final TextStyle textStyleSkip;
  final bool hideSkip;
  final Color colorShadow;
  final double opacityShadow;
  final GlobalKey<TutorialCoachMarkWidgetState> _widgetKey = GlobalKey();
  final Key widgetKey;

  OverlayEntry _overlayEntry;

  TutorialCoachMark(
    this._context,{
    this.targets,this.colorShadow = Colors.black,this.onClickTarget,this.paddingFocus = 10,this.onClickSkip,this.alignSkip = Alignment.bottomRight,this.textSkip = "SKIP",this.textStyleSkip = const TextStyle(color: Colors.white),this.hideSkip = false,this.opacityShadow = 0.8,this.widgetKey
  }) : assert(targets != null,opacityShadow >= 0 && opacityShadow <= 1);

  OverlayEntry _buildOverlay() {
    return OverlayEntry(builder: (context) {
      return TutorialCoachMarkWidget(
        key: _widgetKey,// key: widgetKey,// text: widgetKey,// dua diatas ini tambahan (key nya tadinya pake yang line atas)
        targets: targets,clickTarget: onClickTarget,paddingFocus: paddingFocus,clickSkip: skip,alignSkip: alignSkip,textSkip: textSkip,textStyleSkip: textStyleSkip,hideSkip: hideSkip,colorShadow: colorShadow,opacityShadow: opacityShadow,finish: finish,);
    });
  }

  // @override
  // Widget build(BuildContext context){
  //   show();
  // }

  void show() {
    if (_overlayEntry == null) {
      _overlayEntry = _buildOverlay();
      Overlay.of(_context).insert(_overlayEntry);
    }
  }

  void finish() {
    if (onFinish != null) onFinish();
    _removeOverlay();
  }

  void skip() {
    if (onClickSkip != null) onClickSkip();
    _removeOverlay();
  }

  void next() => _widgetKey?.currentState?.next();
  void previous() => _widgetKey?.currentState?.previous();

  void _removeOverlay() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }
}

这是我要单击的“确定”按钮
class TutorialCoachMarkWidget extends StatefulWidget {
  const TutorialCoachMarkWidget({
    Key key,// this.key = Key('OKE'),this.targets,this.finish,this.clickTarget,this.clickSkip,this.hideSkip,}) : super(key: key);

  final List<TargetFocus> targets;
  final Function(TargetFocus) clickTarget;
  final Function() finish;
  final Color colorShadow;
  final double opacityShadow;
  final double paddingFocus;
  final Function() clickSkip;
  final AlignmentGeometry alignSkip;
  final String textSkip;
  final TextStyle textStyleSkip;
  final bool hideSkip;
  // final Key key; ini diganti sama line 44

  @override
  TutorialCoachMarkWidgetState createState() => TutorialCoachMarkWidgetState();
}

class TutorialCoachMarkWidgetState extends State<TutorialCoachMarkWidget> {
  final GlobalKey<AnimatedFocusLightState> _focusLightKey = GlobalKey();
  final Key textKey = Key('OKE');
  bool showContent = false;
  TargetFocus currentTarget;

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,child: Stack(
        children: <Widget>[
          AnimatedFocusLight(
            key: _focusLightKey,targets: widget.targets,finish: widget.finish,paddingFocus: widget.paddingFocus,colorShadow: widget.colorShadow,opacityShadow: widget.opacityShadow,clickTarget: (target) {
              if (widget.clickTarget != null) widget.clickTarget(target);
            },focus: (target) {
              setState(() {
                currentTarget = target;
                showContent = true;
              });
            },removeFocus: () {
              setState(() {
                showContent = false;
              });
            },AnimatedOpacity(
            opacity: showContent ? 1 : 0,child: _buildContents(),_buildSkip()
        ],);
  }

  Widget _buildContents() {
    if (currentTarget == null) {
      return SizedBox.shrink();
    }

    List<Widget> children = List();

    TargetPosition target = getTargetCurrent(currentTarget);

    var positioned = Offset(
      target.offset.dx + target.size.width / 2,target.offset.dy + target.size.height / 2,);

    double haloWidth;
    double haloHeight;

    if (currentTarget.shape == ShapeLightFocus.Circle) {
      haloWidth = target.size.width > target.size.height
          ? target.size.width
          : target.size.height;
      haloHeight = haloWidth;
    } else {
      haloWidth = target.size.width;
      haloHeight = target.size.height;
    }

    haloWidth = haloWidth * 0.6 + widget.paddingFocus;
    haloHeight = haloHeight * 0.6 + widget.paddingFocus;

    double weight = 0.0;
    double top;
    double bottom;
    double left;

    children = currentTarget.contents.map<Widget>((i) {
      switch (i.align) {
        case AlignContent.bottom:
          {
            weight = MediaQuery.of(context).size.width;
            left = 0;
            top = positioned.dy + haloHeight;
            bottom = null;
          }
          break;
        case AlignContent.top:
          {
            weight = MediaQuery.of(context).size.width;
            left = 0;
            top = null;
            bottom = haloHeight +
                (MediaQuery.of(context).size.height - positioned.dy);
          }
          break;
        case AlignContent.left:
          {
            weight = positioned.dx - haloWidth;
            left = 0;
            top = positioned.dy - target.size.height / 2 - haloHeight;
            bottom = null;
          }
          break;
        case AlignContent.right:
          {
            left = positioned.dx + haloWidth;
            top = positioned.dy - target.size.height / 2 - haloHeight;
            bottom = null;
            weight = MediaQuery.of(context).size.width - left;
          }
          break;
        case AlignContent.custom:
          {
            left = i.customPosition.left;
            top = i.customPosition.top;
            bottom = i.customPosition.bottom;
            weight = MediaQuery.of(context).size.width;
          }
          break;
      }

      return Positioned(
        top: top,bottom: bottom,left: left,child: Container(
          width: weight,child: Padding(
            padding: const EdgeInsets.all(20.0),child: i.child,);
    }).toList();

    return Stack(
      children: children,);
  }

  Widget _buildSkip() {
    if (widget.hideSkip) {
      return SizedBox.shrink();
    }
    return Align(
      alignment: widget.alignSkip,style: widget.textStyleSkip,key: textKey
              ),);
  }
  void next() => _focusLightKey?.currentState?.next();
  void previous() => _focusLightKey?.currentState?.previous();
}

是因为Coach Mark库创建了诸如全屏覆盖之类的东西,所以我无法识别小部件吗?如果可以,我该怎么办?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)