Flutter - Изменить AppBar со страницы
Так что у меня есть приложение Flutter с несколькими страницами, это делается через PageView
, Перед просмотром этой страницы я создаю свой AppBar
поэтому он постоянен в верхней части приложения и не анимируется при прокрутке между страницами. Затем я хочу на одной из страниц создать нижнюю панель приложения, но для этого мне нужен доступ к элементу панели приложения, однако я понятия не имею, как это сделать.
Это основной класс, страница, на которой я пытаюсь редактировать панель приложения, PlanPage
,
final GoogleSignIn googleSignIn = GoogleSignIn();
final FirebaseAuth auth = FirebaseAuth.instance;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '',
home: _handleCurrentScreen()
);
}
Widget _handleCurrentScreen() {
return StreamBuilder<FirebaseUser>(
stream: auth.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
print(snapshot);
if (snapshot.connectionState == ConnectionState.waiting) {
return SplashPage();
} else {
if (snapshot.hasData) {
return Home();
}
return LoginPage();
}
}
);
}
}
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
PageController _pageController;
PreferredSizeWidget bottomBar;
int _page = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: bottomBar,
),
body: PageView(
children: [
Container(
child: SafeArea(
child: RecipesPage()
),
),
Container(
child: SafeArea(
child: PlanPage()
),
),
Container(
child: SafeArea(
child: ShoppingListPage()
),
),
Container(
child: SafeArea(
child: ExplorePage()
),
),
],
/// Specify the page controller
controller: _pageController,
onPageChanged: onPageChanged
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text('Recipes')
),
BottomNavigationBarItem(
icon: Icon(Icons.event),
title: Text('Plan')
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: Text('Shopping List')
),
BottomNavigationBarItem(
icon: Icon(Icons.public),
title: Text("Explore"),
),
],
onTap: navigationTapped,
currentIndex: _page,
),
);
}
void onPageChanged(int page){
setState((){
this._page = page;
});
}
void setBottomAppBar(PreferredSizeWidget appBar) {
this.bottomBar = appBar;
print("setBottomAppBar: "+ appBar.toString());
}
/// Called when the user presses on of the
/// [BottomNavigationBarItem] with corresponding
/// page index
void navigationTapped(int page){
// Animating to the page.
// You can use whatever duration and curve you like
_pageController.animateToPage(
page,
duration: const Duration(milliseconds: 300),
curve: Curves.ease
);
}
@override
void initState() {
super.initState();
initializeDateFormatting();
_pageController = PageController();
}
@override
void dispose(){
super.dispose();
_pageController.dispose();
}
}
PlanPage
класс выглядит так
class PlanPage extends StatefulWidget {
var homeState;
PlanPage(this.homeState);
@override
State<StatefulWidget> createState() {
return _PlanState(homeState);
}
}
class _PlanState extends State<PlanPage> with AutomaticKeepAliveClientMixin<PlanPage>, SingleTickerProviderStateMixin {
var homeState;
TabController _tabController;
_PlanState(this.homeState);
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
//homeState.setBottomAppBar(_buildTabBar());
return Scaffold(
appBar: AppBar(
bottom: _buildTabBar(),
),
body: TabBarView(
controller: _tabController,
children: Plan.now().days.map((day) {
return ListView.builder(
itemCount: MealType.values.length,
itemBuilder: (BuildContext context, int index){
var mealType = MealType.values[index];
return Column(
children: <Widget>[
Text(
mealType.toString().substring(mealType.toString().indexOf('.')+1),
style: TextStyle(
//decoration: TextDecoration.underline,
fontSize: 30.0,
fontWeight: FontWeight.bold
),
),
Column(
children: day.meals.where((meal) => meal.mealType == mealType).map((meal) {
return RecipeCard(meal.recipe);
}).toList(),
)
],
);
}
);
}).toList(),
)
);
}
Widget _buildTabBar() {
return TabBar(
controller: _tabController,
isScrollable: true,
tabs: List.generate(Plan.now().days.length,(index) {
return Tab(
child: Column(
children: <Widget>[
Text(DateFormat.E().format(Plan.now().days[index].day)),
Text(DateFormat('d/M').format(Plan.now().days[index].day)),
],
),
);
}, growable: true),
);
}
@override
void initState() {
super.initState();
_tabController = new TabController(
length: Plan.now().days.length,
vsync: this,
initialIndex: 1
);
}
}
Однако то, как он работает сейчас, позволяет отображать 2 панели приложений.[
1 ответ
Обычно не рекомендуется иметь две вложенные прокручиваемые области. То же самое для двух вложенных лесов.
Тем не менее, вы можете слушать изменения страницы (_pageController.addListener(listener)
) обновить page
государственная собственность, и построить другую AppBar.bottom
(в Home
виджет, так что вы можете удалить эшафот в PlanPage
) в зависимости от страницы, которую просматривает пользователь.
-РЕДАКТИРОВАТЬ-
В вашем Home
виджет вы можете добавить слушателя к _pageController
вот так:
void initState() {
super.initState();
_pageController = PageController()
..addListener(() {
setState(() {});
});
}
чтобы ваш виджет перестраивался каждый раз, когда пользователь прокручивает внутри вашего PageView
, setState
вызов с пустой функцией может выглядеть запутанным, но он просто позволяет перестроить виджет, когда _pageController.page
изменения, что не является поведением по умолчанию. Вы также можете иметь page
государственной собственности и обновить его в setState
призыв отражать _pageController.page
собственности, но результат будет таким же.
Таким образом, вы можете построить другой AppBar.bottom
в зависимости от _pageController.page
:
// in your build function
final bottomAppBar = _pageController.page == 2 ? TabBar(...) : null;
final appBar = AppBar(
bottom: bottomAppBar,
...
);
return Scaffold(
appBar: appBar,
...
);