【问题标题】:Multi tab / page view in flutter颤动中的多标签/页面视图
【发布时间】:2018-02-13 00:22:27
【问题描述】:

如何在 Flutter 中创建多页面视图,其中页面对应于底部导航栏中的选项卡,以便与页面对应的小部件仅按需构建一次。

例如,考虑一个简单的 facebook 应用程序类型的 UI,它有两个选项卡 - 提要和具有以下行为的通知:

  1. 提要和通知都是通过网络获取的项目列表。
  2. 假设原始标签是提要,只有当用户点击通知标签时才会获取通知
  3. 如果用户在提要中滚动,然后单击通知图标,然后再次单击提要图标,则应记住滚动位置。

如果我使用 TabBarView,它会在每次更改选项卡时重建小部件,因此不会保留滚动位置。

【问题讨论】:

标签: flutter


【解决方案1】:

要为TabBarView 的页面提供唯一的滚动位置存储容器,请使用PageStorageKey

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State createState() => new MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  TabController _controller;
  int _tab = 0;

  @override
  void initState() {
    _controller = new TabController(length: 2, vsync: this);
  }

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Example App')),
      body: new TabBarView(
        controller: _controller,
        children: <Widget>[
          new ListView.builder(
            key: new PageStorageKey('feed'),
            itemBuilder: (BuildContext context, int index) {
              return new ListTile(
                title: new Text('Feed Item $index'),
              );
            },
          ),
          new ListView.builder(
            key: new PageStorageKey('notifications'),
            itemBuilder: (BuildContext context, int index) {
              return new ListTile(
                title: new Text('Notification $index'),
              );
            },
          ),
        ],
      ),
      bottomNavigationBar: new BottomNavigationBar(
        onTap: (int value) {
          _controller.animateTo(value);
          setState(() {
            _tab = value;
          });
        },
        currentIndex: _tab,
        items: <BottomNavigationBarItem>[
          new BottomNavigationBarItem(
            icon: new Icon(Icons.home),
            title: new Text('Home'),
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.notifications),
            title: new Text('Notifications'),
          ),
        ],
      ),
    );
  }
}

【讨论】:

  • 这是否适用于分页列表(无限滚动列表)?
【解决方案2】:

完整示例

首先创建一个 MyBottomBarDemo 类

class MyBottomBarDemo extends StatefulWidget {
  @override
  _MyBottomBarDemoState createState() => new _MyBottomBarDemoState();
}

class _MyBottomBarDemoState extends State<MyBottomBarDemo> {
  int _pageIndex = 0;
  PageController _pageController;

  List<Widget> tabPages = [
    Screen1(),
    Screen2(),
  ];

  @override
  void initState(){
    _pageController = PageController(initialPage: _pageIndex);
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
    _pageController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Multi tab / page view", style: TextStyle(color: Colors.white)),
        backgroundColor: Colors.deepPurple,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _pageIndex,
        onTap: onTabTapped,
        backgroundColor: Colors.white,
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem( icon: Icon(Icons.home), title: Text("Home")),
          BottomNavigationBarItem(icon: Icon(Icons.mail), title: Text("Messages")),
        ],

      ),
      body: PageView(
        children: tabPages,
        onPageChanged: onPageChanged,
        controller: _pageController,
      ),
      drawer: SlideDrawer(),
    );
  }
  void onPageChanged(int page) {
    setState(() {
      this._pageIndex = page;
    });
  }

  void onTabTapped(int index) {
    this._pageController.animateToPage(index,duration: const Duration(milliseconds: 500),curve: Curves.easeInOut);
  }
}

然后创建一个寻呼机屏幕

class Screen1(), extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.yellow,
      child: StreamBuilder(
        stream: getHomeDataList(param).asStream(), // This is your function of get data from network
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting: {
                return LoadingIndicatorView();
              }
            case ConnectionState.active: {
                break;
              }
            case ConnectionState.done: {
                if (snapshot.hasData) {
                  if (snapshot.data != null) {
                    if (snapshot.data.length > 0) {
                      return Container(
                        color: offBlueColor,
                        child: Scrollbar(
                          child: ListView.builder(
                              key: PageStorageKey('homeList'),
                              padding: EdgeInsets.all(5),
                              itemCount: snapshot.data.length,
                              itemBuilder: (context, index) {
                                return ListTile(
                                  title: Text('Home Page index $index')
                                );;
                              }),
                        ),
                      );
                    } else {
                      return Text("No data found");
                    }
                  } else {
                    // display error message data is null.
                    return Text("No data found");
                  }
                } else if (snapshot.hasError) {
                  return Text(snapshot.error.toString());
                } else {
                  return Text("Something went wrong");
                }
                break;
              }
            case ConnectionState.none:{
                break;
              }
          }
          return Container();
        },
      ),
    );
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-24
    • 2023-04-01
    • 2022-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多