我已经从我的 IDE 构建了一个在调试和发布模式下运行良好的 Flutter Web 应用程序。但是,托管后我在其中一个小部件中看到灰屏。
我知道这个问题已经被问过很多次了,通常它会缩小到在调试模式下运行并检查日志是否存在任何问题,例如父小部件、扩展、灵活等...
我根本没有看到任何错误或警告。
但是,如果我在托管模式下运行 F12,我会看到以下错误:
异常:找不到 APP_TYPE 变量。缺失条目需要非空回退
除此之外,在我的 IDE 构建的调试/发布模式下完全没有问题。
在此处复制有问题的小部件代码:
Expanded(
flex: 3,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedPackageStatusButton(
index: 0,
selectedIndex: _selectedPackageStatusIndex,
onChange: (idx) =>
selectPackageStatusAction(idx, context),
title: paymentStatusName[
PaymentStatus.values[0]]!
.translate(context),
// packageStatus: getPackageStatusByIndex(0),
),
context.getResponsiveValue(12).hSpace,
AnimatedPackageStatusButton(
index: 1,
selectedIndex: _selectedPackageStatusIndex,
onChange: (idx) =>
selectPackageStatusAction(idx, context),
title: paymentStatusName[
PaymentStatus.values[1]]!
.translate(context),
// packageStatus: getPackageStatusByIndex(1),
),
],
),
context.getResponsiveValue(16).vSpace,
Expanded(
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: context.colorsTheme.tabBar,
borderRadius: BorderRadius.only(
topLeft: context
.getResponsiveValue(16)
.cRadius,
topRight: context
.getResponsiveValue(16)
.cRadius,
),
),
child: Column(
children: [
PackagesListWidget(
editPackageAction: (Package package) =>
showEditPackageCostModal(package),
packagesList: tabPackagesList,
isItemDisabled: true,
onChecked: (newValue, package) {
int idx =
tabPackagesList.indexOf(package);
setState(
() {
tabPackagesList.removeAt(idx);
tabPackagesList.insert(
idx,
package.copyWith(
isChecked: newValue),
);
},
);
},
),
AnimatedSwitcher(
duration:
const Duration(milliseconds: 300),
child: tabPackagesList.isNotEmpty
? StoreBillingPackagesListFooterActions(
packagesList: tabPackagesList
.where((p) => p.isChecked)
.toList(),
showPrint:
_selectedPackageStatusIndex ==
0,
updateFunc: () => {
setState(() {
updateTabPackages(
context);
})
})
: const SizedBox.shrink(),
),
],
),
),
),
],
),
),
上面使用的 2 个小部件是。 1 包列表小部件
Expanded(
child: widget.packagesList.isEmpty
? EmptyListContainer(
title: 'noPackagesFoundMessage'.translate(context),
)
: ListView.separated(
padding: EdgeInsets.symmetric(
vertical: context.responsiveValue(
mobile: context.getResponsiveValue(20),
largeTablet: 0,
),
),
itemCount: widget.packagesList.length,
itemBuilder: (BuildContext context, int index) {
return PackageListItem(
package: widget.packagesList[index],
selectPackageAction: widget.selectPackageAction,
isSelected:
widget.selectedPackage == widget.packagesList[index],
isDisabled: widget.isItemDisabled,
onChecked: widget.onChecked,
editPackageAction: // todo: this condition should not be inside the package list in this case you can not use the edit in the future for such status
widget.packagesList[index].paymentStatus !=
PaymentStatus.paid
? widget.editPackageAction
: null,
);
},
separatorBuilder: (BuildContext context, int index) {
return context.responsiveValue(
mobile: context.getResponsiveValue(12).vSpace,
largeTablet: Divider(
color: context.colorsTheme.background,
),
);
},
),
);
和页脚:
BlocListener<PackagesBloc, PackagesState>(
listener: (context, state) {
if (state.status == PackagesStatus.loading) {
log('loading packages');
context.read<GlobalLoadingBloc>().add(GlobalStartLoading());
} else if (state.status == PackagesStatus.failed) {
log('loading packages');
context.read<GlobalLoadingBloc>().add(GlobalEndLoading());
showFlashMessage(
flashType: FlashType.error,
bodyText: state.message.translate(context),
);
} else {
context.read<GlobalLoadingBloc>().add(GlobalEndLoading());
updateFunc();
showFlashMessage(
flashType: FlashType.success,
bodyText: "packagesMarkedAsPaidMsg".translate(context),
);
}
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: context.getResponsiveValue(16),
vertical: context.getResponsiveValue(16),
),
decoration: BoxDecoration(
color: context.colorsTheme.secondary,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(
context.getResponsiveValue(16),
),
topRight: Radius.circular(
context.getResponsiveValue(16),
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
"${'totalSelectedPackages'.translate(context)}: ",
style: context.textTheme.normalMedium.copyWith(
color: context.colorsTheme.onSecondary,
),
),
context.getResponsiveValue(8).hSpace,
Text(
packagesList.length.toString(),
style: context.textTheme.boldMedium.copyWith(
color: context.colorsTheme.onSecondary,
),
),
],
),
Row(
children: [
Text(
"${'totalToPay'.translate(context)}: ",
style: context.textTheme.normalMedium.copyWith(
color: context.colorsTheme.onSecondary,
),
),
Text(
(packagesList.fold(
0.0,
(previousValue, element) =>
previousValue + element.cost)).toStringAsFixed(2),
style: context.textTheme.boldMedium.copyWith(
color: context.colorsTheme.onSecondary,
),
),
],
),
],
),
!showPrint || packagesList.isEmpty
? const SizedBox.shrink()
: Link(
text: 'markSelectedAsPaid'.translate(context),
onTap: () {
showMarkPackageAsPaidModal(context);
},
textColor: context.colorsTheme.onSecondary,
),
!showPrint || packagesList.isEmpty
? const SizedBox.shrink()
: Link(
text: 'printSelected'.translate(context),
onTap: () {
context.push(
RoutePaths.packagePDFScreenRoute.path,
extra: {
"packagesList": packagesList,
"summary": true,
"pdfFor": "store",
},
);
},
textColor: context.colorsTheme.onSecondary,
),
],
),
),
);
查看您的小部件树,我可以看到其中一个
Expanded
小部件位于 Padding
小部件内。
PackageListItem -> Row -> Padding -> Expanded
这一定会导致
Invalid Parent data widget exception
产生“灰屏”问题。请参阅附图,指出问题所在的树的确切级别。
尝试将
Expanded
直接放在 Row
下方,然后将其包裹在 Padding
下
参考:https://docs.flutter.dev/testing/common-errors#in Correct-use-of-parentdata-widget[在此处输入图像描述]1