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

1 ответ

Решение

Обычно не рекомендуется иметь две вложенные прокручиваемые области. То же самое для двух вложенных лесов.

Тем не менее, вы можете слушать изменения страницы (_pageController.addListener(listener)) обновить page государственная собственность, и построить другую AppBar.bottomHome виджет, так что вы можете удалить эшафот в 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,
    ...
);
Другие вопросы по тегам