首页 文章

在PageView上展开持久的应用栏

提问于
浏览
1

理想情况下,我想按如下方式设置我的Flutter应用程序

  • PageView可在3页和左下导航栏之间向左/向右滑动以作为标签,也可帮助导航

  • 持久性appbar位于顶部,带有抽屉和上下文图标

  • 之间的页面内容

从图像中可以看出,我主要通过以下方式设置我想要的方式

main.dart - app entry point, set up appbar, set up pageview with children for new PeoplePage, new TimelinePage, new StatsPage

people_page.dart
timeline_page.dart
stats_page.dart

These three pages just deliver the content to the PageView children as required.

这是实现这一目标的正确方法吗?表面上它工作正常 . 我遇到的问题是,在人员页面上,我想实现一个可更改appbar Headers /颜色as in this example的可选列表,但appbar是在主页面上设置的 . 我可以全局访问appbar吗?

我可以为每个页面构建一个新的appbar,但我不希望在切换页面时刷新新的appbar . 我更喜欢appbar看起来持久,只有内容滑动 .

任何关于实现这一目标的最佳方法的指导将不胜感激 .

sample

2 回答

  • 5

    我汇总了一个快速示例,说明如何从屏幕向下与页面进行通信,然后再返回 . 这应该可以解决您的问题 .

    https://gist.github.com/slightfoot/464fc225b9041c2d66ec8ab36fbdb935

    import 'package:flutter/material.dart';
    
    void main() => runApp(TestApp());
    
    class TestApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(
            primaryColor: Colors.green[900],
            scaffoldBackgroundColor: Colors.grey[200],
          ),
          home: MainScreen(),
        );
      }
    }
    
    class AppBarParams {
      final Widget title;
      final List<Widget> actions;
      final Color backgroundColor;
    
      AppBarParams({
        this.title,
        this.actions,
        this.backgroundColor,
      });
    } 
    
    class MainScreen extends StatefulWidget {
      final int initialPage;
    
      const MainScreen({
        Key key,
        this.initialPage = 0,
      }) : super(key: key);
    
      @override
      MainScreenState createState() => MainScreenState();
    
      static MainScreenState of(BuildContext context) {
        return context.ancestorStateOfType(TypeMatcher<MainScreenState>());
      }
    }
    
    class MainScreenState extends State<MainScreen> {
      final List<GlobalKey<MainPageStateMixin>> _pageKeys = [
        GlobalKey(),
        GlobalKey(),
        GlobalKey(),
      ];
    
      PageController _pageController;
      AppBarParams _params;
      int _page;
    
      set params(AppBarParams value) {
        setState(() => _params = value);
      }
    
      @override
      void initState() {
        super.initState();
        _page = widget.initialPage ?? 0;
        _pageController = PageController(initialPage: _page);
        WidgetsBinding.instance.addPostFrameCallback((_) {
          _pageKeys[0].currentState.onPageVisible();
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: _params?.title,
            actions: _params?.actions,
            backgroundColor: _params?.backgroundColor,
          ),
          body: PageView(
            controller: _pageController,
            onPageChanged: _onPageChanged,
            children: <Widget>[
              PeoplePage(key: _pageKeys[0]),
              TimelinePage(key: _pageKeys[1]),
              StatsPage(key: _pageKeys[2]),
            ],
          ),
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: _page,
            onTap: _onBottomNavItemPressed,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                title: Text('people'),
                icon: Icon(Icons.people),
              ),
              BottomNavigationBarItem(
                title: Text('timeline'),
                icon: Icon(Icons.history),
              ),
              BottomNavigationBarItem(
                title: Text('stats'),
                icon: Icon(Icons.pie_chart),
              ),
            ],
          ),
        );
      }
    
      @override
      void reassemble() {
        super.reassemble();
        _onPageChanged(_page);
      }
    
      void _onPageChanged(int page) {
        setState(() => _page = page);
        _pageKeys[_page].currentState.onPageVisible();
      }
    
      void _onBottomNavItemPressed(int index) {
        setState(() => _page = index);
        _pageController.animateToPage(
          index,
          duration: Duration(milliseconds: 400),
          curve: Curves.fastOutSlowIn,
        );
      }
    }
    
    abstract class MainPageStateMixin<T extends StatefulWidget> extends State<T> {
      void onPageVisible();
    }
    
    class PeoplePage extends StatefulWidget {
      const PeoplePage({Key key}) : super(key: key);
    
      @override
      PeoplePageState createState() => PeoplePageState();
    }
    
    class PeoplePageState extends State<PeoplePage> with MainPageStateMixin {
      final List<Color> _colors = [
        Colors.orange,
        Colors.purple,
        Colors.green,
      ];
    
      int _personCount = 3;
    
      @override
      void onPageVisible() {
        MainScreen.of(context).params = AppBarParams(
          title: Text('People'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.person_add),
              onPressed: () => setState(() => _personCount++),
            ),
          ],
          backgroundColor: Colors.green,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemCount: _personCount,
          itemBuilder: (BuildContext context, int index) {
            return Card(
              child: InkWell(
                onTap: () => _onTapCard(index),
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Material(
                        type: MaterialType.circle,
                        color: _colors[index % _colors.length],
                        child: Container(
                          width: 48.0,
                          height: 48.0,
                          alignment: Alignment.center,
                          child: Text('$index', style: TextStyle(color: Colors.white)),
                        ),
                      ),
                      SizedBox(width: 16.0),
                      Text(
                        'Item #$index',
                        style: TextStyle(
                          color: Colors.grey[600],
                          fontSize: 18.0,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          },
        );
      }
    
      void _onTapCard(int index) {
        Scaffold.of(context).showSnackBar(SnackBar(content: Text('Item #$index')));
      }
    }
    
    class TimelinePage extends StatefulWidget {
      const TimelinePage({Key key}) : super(key: key);
    
      @override
      TimelinePageState createState() => TimelinePageState();
    }
    
    class TimelinePageState extends State<TimelinePage> with MainPageStateMixin {
      @override
      void onPageVisible() {
        MainScreen.of(context).params = AppBarParams(
          title: Text('Timeline'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.alarm_add),
              onPressed: () {},
            ),
          ],
          backgroundColor: Colors.purple,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text('Coming soon'),
        );
      }
    }
    
    class StatsPage extends StatefulWidget {
      const StatsPage({Key key}) : super(key: key);
    
      @override
      StatsPageState createState() => StatsPageState();
    }
    
    class StatsPageState extends State<StatsPage> with MainPageStateMixin {
      @override
      void onPageVisible() {
        MainScreen.of(context).params = AppBarParams(
          title: Text('Stats'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.add_box),
              onPressed: () {},
            ),
          ],
          backgroundColor: Colors.orange,
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Text('Coming soon'),
        );
      }
    }
    
  • 1

    解决这个问题的一种方法是将AppBar Headers 和背景颜色作为状态变量,并在PageView中将onPageChanged设置为函数 . 此函数接受页面int并基于页面int将 Headers 和颜色的状态设置为所需的值 . 对于多选列表,您将 Headers 设置为保留所选值的变量,可以将其保留为主页面中的状态变量,并将其传递给子组件 . 您可以使用任何状态管理策略,这应该可以正常工作 .

    onPageChanged函数示例:

    void onPageChanged(int page) {
        String _temptitle = "";
        Color _tempColor;
        switch (page) {
          case 0:
            _temptitle = "People";
            _tempColor = Colors.pink;
            break;
          case 1:
            _temptitle = "Timeline";
            _tempColor = Colors.green;
            break;
          case 2:
            _temptitle = "Stats";
            _tempColor = Colors.deepPurple;
            break;
        }
        setState(() {
          this._page = page;
          this._title = _temptitle;
          this._appBarColor = _tempColor;
        });
      }
    

    因此,对于多选案例,不是将 Headers 设置为某个常量,而是将 Headers 设置为包含所选选项值的变量 .

    Sample here

    完整代码在这里:

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      PageController _pageController;
      int _page = 0;
      String _title = "MyApp";
      Color _appBarColor = Colors.pink;
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text(_title),
            backgroundColor: _appBarColor,
          ),
          body: PageView(
            children: <Widget>[
              Container(
                child: Center(child: Text("People")),
              ),
              Container(
                child: Center(child: Text("Timeline")),
              ),
              Container(
                child: Center(child: Text("Stats")),
              ),
            ],
            controller: _pageController,
            onPageChanged: onPageChanged,
          ),
          bottomNavigationBar: BottomNavigationBar(
            items: [
              BottomNavigationBarItem(
                icon: Icon(Icons.people),
                title: Text("People"),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.access_time),
                title: Text("Timeline"),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.pie_chart),
                title: Text("Stats"),
              ),
            ],
            onTap: navigateToPage,
            currentIndex: _page,
          ),
        );
      }
    
      void navigateToPage(int page) {
        _pageController.animateToPage(page,
            duration: Duration(milliseconds: 300), curve: Curves.ease);
      }
    
      void onPageChanged(int page) {
        String _temptitle = "";
        Color _tempColor;
        switch (page) {
          case 0:
            _temptitle = "People";
            _tempColor = Colors.pink;
            break;
          case 1:
            _temptitle = "Timeline";
            _tempColor = Colors.green;
            break;
          case 2:
            _temptitle = "Stats";
            _tempColor = Colors.deepPurple;
            break;
        }
        setState(() {
          this._page = page;
          this._title = _temptitle;
          this._appBarColor = _tempColor;
        });
      }
    
      @override
      void initState() {
        super.initState();
        _pageController = new PageController();
        _title = "People";
      }
    
      @override
      void dispose() {
        super.dispose();
        _pageController.dispose();
      }
    }
    

    您可以根据需要改进此代码 . 希望这对某些方面有帮助 . 如果有什么我可以改进这个答案,请告诉我 .

相关问题