Я создал веб-приложение Flutter, которое отлично работает в режиме отладки и выпуска из моей IDE. Однако после хостинга я вижу серый экран в одном из виджетов.
Я знаю, что этот вопрос задавался много раз, и обычно он сводится к запуску в режиме отладки и проверке журнала на наличие каких-либо проблем, таких как родительский виджет, расширенный, гибкий и т. д.
Я вообще не вижу никаких ошибок или предупреждений.
Однако если я запущу 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(),
),
],
),
),
),
],
),
),
Два виджета, использованные выше: 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
.
Привет, спасибо! Заполнение только дочернего элемента строки, а расширенное - это другой дочерний элемент. расширенное не является дочерним элементом заполнения в PackageListItem
Я нашел проблему, пожалуйста, посмотрите решение в ответе ниже.
@Saeedisa Ты прав. Я неправильно понял дерево. Спасибо что подметил это
Это использование .env!
очевидно, веб-приложение не поддерживает файлы .env, файлы должны быть .env, я переименовал файл в dotenv_prod.env (и изменил соответствующие варианты использования), и все сработало!
Я взял ответ из этой ветки переполнения стека, полагаясь на ответ и комментарий Кельвина Джоу.
Без кода невозможно понять, почему