Flutter - 从页面修改AppBar

Flutter - Modify AppBar from a page

所以我有一个包含多个页面的 Flutter 应用程序,这是通过 PageView 完成的。在此页面视图之前,我创建了我的 AppBar,因此它在应用程序的顶部持久存在,并且在页面之间滚动时不会显示动画。 然后我想在其中一个页面上创建一个底部应用栏,但为此我需要访问应用栏元素,但我不知道该怎么做。

这是主要 class,我试图在其上编辑应用栏的页面是 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();
    }
}

PlanPageclass看起来像这样

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 个应用程序栏。[

通常,拥有两个嵌套的可滚​​动区域并不是最佳做法。两个嵌套的脚手架也一样。

也就是说,您可以侦听页面更改 (_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 属性,但结果是相同的。

这样你可以根据 _pageController.page:

构建不同的 AppBar.bottom
// in your build function

final bottomAppBar = _pageController.page == 2 ? TabBar(...) : null;

final appBar = AppBar(
    bottom: bottomAppBar,
    ...
);

return Scaffold(
    appBar: appBar,
    ...
);