问题描述
我正在为使用CoachMark库(https://pub.dev/packages/tutorial_coach_mark)的应用程序使用Flutter驱动程序编写集成测试
我想单击文本以关闭CoachMark,但是当我尝试使用VSCode的窗口小部件检查器对其进行检查时,文本没有显示在窗口小部件树上,当我将检查器悬停在该文本上时,它指向MaterialApp
根小部件(请参见屏幕截图)
这些是我尝试找不到运气的方法:
-
find.byType('Text')
-
find.text('OKE')
-
find.byType('RichText')
- 甚至是这个嵌套的,令人困惑的发现者
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
),),);
}
我附加了一个屏幕截图,以显示我要单击的内容(屏幕右下角的文字)
有什么建议吗?
修改
这是主屏幕:
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 (将#修改为@)