【问题标题】:Flutter - Modify AppBar from a pageFlutter - 从页面修改 AppBar
【发布时间】:2019-04-26 21:55:27
【问题描述】:

所以我有一个包含多个页面的 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 个应用栏。[

【问题讨论】:

    标签: flutter flutter-appbar


    【解决方案1】:

    通常,拥有两个嵌套的可滚​​动区域并不是最佳做法。两个嵌套的 Scaffold 也是如此。

    也就是说,您可以监听页面更改 (_pageController.addListener(listener)) 以更新 page 状态属性,并构建不同的 AppBar.bottom(在 Home 小部件中,因此您可以删除 @987654325 中的脚手架@) 取决于用户正在查看的页面。

    -编辑-

    在您的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,
        ...
    );
    

    【讨论】:

    • 我真的无法让它工作。我不知道应该在哪里构建我的 TabController,所以我仍然可以将它提供给 AppBar.bottom
    • 您可以简单地将其移动到Home 小部件并将其作为构造函数参数传递给PlanPage
    • 在我的 Home 小部件中包含所有这些逻辑并不那么优雅,当该逻辑特定于 PlanPage 时,另一个页面也需要一个 Tabcontroller。因此,Tabcontroller 是否处于另一个状态对象然后是实际使用它的对象并不重要?
    • 不用等待,您必须根据用户正在查看的Home 小部件中的PageView 中的哪个页面来显示不同的AppBar.bottom,对吗?因此,在Home 小部件中,您将拥有带有侦听器的pageController,而tabController 将保留在PlanPage 中。
    猜你喜欢
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 2020-09-25
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 2020-01-02
    相关资源
    最近更新 更多