#flutter #setstate #tabbar #bottomnavigationview
#flutter #setstate #панель вкладок #bottomnavigationview
Вопрос:
У меня есть следующая Flutter BottomNavigationBar, у меня есть 3 виджета дочерних страниц. Как только пользователь пишет отзыв и нажимает кнопку отправки, я вызываю void _clear(), который сбрасывает значения в виджетах текстового поля. Этот метод находится внутри и вызывается из виджета WriteReview, но не работает, экран не обновляется. Данные, которые он сам сбрасывает, но пользовательский интерфейс не обновляется. Я пробовал с setState(){ _clear()} и без него; но никаких результатов.
У меня аналогичная проблема с TabBarView. В результате я ожидал бы обновления выбранной страницы виджета.
Я предполагаю, что есть что-то другое в том, как обрабатываются виджеты в TabBarView и BottomNavigationBar, чего мне не хватает.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomeView extends StatefulWidget {
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final String _writeReviewLabel = 'Write review';
final String _searchLabel = 'Search';
final String _accountLabel = 'Account';
var _currentIndex = 0;
final List<Widget> _bottomBarItems = [
WriteReviewView(),
SearchView(),
UserAccountView()
];
@override
Widget build(BuildContext context) {
final accentColor = Theme.of(context).accentColor;
final primaryColor = Theme.of(context).primaryColor;
return BaseView<HomePresenter>(
createPresenter: () => HomePresenter(),
onInitialize: (presenter) {
_currentIndex = ModalRoute.of(context).settings.arguments;
},
builder: (context, child, presenter) => Scaffold(
bottomNavigationBar: BottomNavigationBar(
backgroundColor: primaryColor,
selectedItemColor: accentColor,
unselectedItemColor: Colors.white,
elevation: 0,
currentIndex: _currentIndex,
onTap: (index) {
onTabTapped(index, presenter);
},
items: [
BottomNavigationBarItem(
activeIcon: Icon(Icons.rate_review),
icon: Icon(Icons.rate_review),
title: Text(_writeReviewLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.search),
icon: Icon(Icons.search),
title: Text(_searchLabel),
),
BottomNavigationBarItem(
activeIcon: Icon(Icons.person),
icon: Icon(Icons.person),
title: Text(_accountLabel)),
],
),
body: _bottomBarItems[_currentIndex]),
);
}
void onTabTapped(int index, HomePresenter presenter) {
if (index == _currentIndex) {
return;
}
if (presenter.isAuthenticated) {
setState(() {
_currentIndex = index;
});
} else {
presenter.pushNamed(context, Routes.login, arguments: () {
if (presenter.isAuthenticated) {
Future.delayed(const Duration(microseconds: 500), () {
setState(() {
_currentIndex = index;
});
});
}
});
}
}
}
Просмотр записи обзора
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'base/BaseView.dart';
class WriteReviewView extends StatefulWidget {
@override
_WriteReviewViewState createState() => _WriteReviewViewState();
}
class _WriteReviewViewState extends State<WriteReviewView> {
final String _locationLabel = 'Location';
final String _reviewLabel = 'Review';
@override
Widget build(BuildContext context) {
return BaseView<WriteReviewPresenter>(
createPresenter: () => WriteReviewPresenter(),
onInitialize: (presenter) {
presenter.init();
},
builder: (context, child, presenter) => Container(
color: Theme.of(context).backgroundColor,
child: _body(presenter),
));
}
Widget _body(WriteReviewPresenter presenter) {
final height = MediaQuery.of(context).size.height;
return LayoutBuilder(builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10, bottom: 20),
child: Row(
children: [
Icon(Icons.location_on,
color: Theme.of(context).cursorColor),
SectionTitle(_locationLabel),
],
),
),
ChooseAddressButton(presenter.addressContainer.address, () {
presenter.navigateNewAddress(context);
}),
SizedBoxes.medium,
],
),
),
),
Card(
margin: EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 8.0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 10),
child: Row(
children: [
Icon(Icons.star, color: Theme.of(context).indicatorColor),
SectionTitle(_reviewLabel),
],
),
),
SizedBoxes.medium,
CustomTextFormField(
data: presenter.reviewContainer.review,
showMinimum: true,
characterLimit: 50,
maxLines: 4,
height: 100),
ModifyRatingBar(50.0, presenter.reviewContainer.rating, false),
Padding(
padding: EdgeInsets.symmetric(vertical: 5),
child: Divider(indent: 40, endIndent: 40)),
],
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Card(
color: Theme.of(context).accentColor,
child: FlatButton(
onPressed: () {
_submit(context, presenter);
},
child: Text('Submit',style:TextStyle(fontWeight: FontWeight.bold,fontSize: 18,color: Colors.white)),
),
),
),
],
),
),
),
);
});
}
void _submit(BuildContext context, WriteReviewPresenter presenter) async {
LoadingPopup.show(context);
final status = await presenter.submit(context);
LoadingPopup.hide(context);
if (status == ReviewStatus.successful) {
PostCompletePopup.show(context);
setState(() {
presenter.clear();
});
} else {
presenter.showError(context, status);
}
}
}
Ответ №1:
setState()
обновляется только виджет, который его вызвал, и все виджеты под ним.
При вызове setState()
из WriteReview
виджета он не обновит HomeView
виджет. Попробуйте переместить setState()
вызов на HomeView
виджет, используя какой-либо обратный вызов.
Комментарии:
1. Итак, тот факт, что WriteReview является частью HomeView как элемента BottomNavigationBarItem, возлагает на home view ответственность за обновление дочернего пользовательского интерфейса? Разве это не противоречит интуиции при сравнении остальной части проекта? Во всех остальных случаях set state обновляет вызывающий виджет, как и предполагалось. Я хочу понять, почему на дочерних страницах TabBarView и BottomBarNavigation setstate не работает, это специальное правило для этих контроллеров?
2. возможно, я неправильно понял. можете ли вы поделиться кодом, который не работает в виджете writereview?
3. Я обновил свой первоначальный пост, проблема связана с методом в end _submit, вызов «presenter.clear()» просто устанавливает строки в пустые, а значение строки оценки в 0. Я добавил журналы отладки, и значения действительно изменились, хотя пользовательский интерфейс не отражает это изменение. Я попытался обернуть это внутри setstate, но пользовательский интерфейс по-прежнему не обновляется. У меня точно такая же проблема в другом представлении с TabBarView, дочерние виджеты не обновляются после setstate и изменения