1

这是我在 StackOverflow 上提出的第一个问题,我希望我能提供正确回答所需的一切。

我正在构建 Instagram 克隆,我想使用 CupertinoTabBar 来模仿 Instagram 的应用行为。

Instagram 上的行为: Gif

目前的主要挑战是我想通过点击 NavigationBar 上的图标来显示整页对话以创建帖子。通常,我会使用如下代码:

Navigator.of(
          context,
          rootNavigator: true,
        ).push<...>(
          SlidePageTransitionBuilder<...>(
            builder: ...,
            transitionCurve: routeCurve,
            transitionDuration: routeDuration,
          ),
        );

但不幸的是,我无法将此 Navigator.push 放在按下的条形图标上,因为它需要一个返回类型的小部件,我不知道如何在具有预期行为的同时提供它。

非常感谢某人的帮助。如果您需要更多信息,请告诉我。

示例项目代码:

Git Hub 仓库

主要飞镖:

import 'package:flutter/material.dart';

import 'cupertino_home_scaffold.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TabItem _currentTab = TabItem.timeline;

  final Map<TabItem, GlobalKey<NavigatorState>> navigatorKeys = {
    TabItem.timeline: GlobalKey<NavigatorState>(),
    TabItem.map: GlobalKey<NavigatorState>(),
    TabItem.share: GlobalKey<NavigatorState>(),
    TabItem.account: GlobalKey<NavigatorState>(),
  };

  Map<TabItem, WidgetBuilder> get widgetBuilders {
    return {
      TabItem.timeline: (_) => SomePage(),
      TabItem.map: (_) => SomePage(),
      TabItem.share: (context) =>
          PostPage(), //Should be displayed with Navigator.push...,
      TabItem.account: (_) => SomePage(),
    };
  }

  void _select(TabItem tabItem) {
    if (tabItem == _currentTab) {
      navigatorKeys[tabItem].currentState.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentTab = tabItem;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async =>
          !await navigatorKeys[_currentTab].currentState.maybePop(),
      child: CupertinoHomeScaffold(
        navigatorKeys: navigatorKeys,
        currentTab: _currentTab,
        onSelectTab: _select,
        widgetBuilders: widgetBuilders,
      ),
    );
  }
}

cupertino_home_scaffold.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class CupertinoHomeScaffold extends StatelessWidget {
  const CupertinoHomeScaffold({
    Key key,
    @required this.currentTab,
    @required this.onSelectTab,
    @required this.widgetBuilders,
    @required this.navigatorKeys,
  }) : super(key: key);

  final TabItem currentTab;
  final ValueChanged<TabItem> onSelectTab;
  final Map<TabItem, WidgetBuilder> widgetBuilders;
  final Map<TabItem, GlobalKey<NavigatorState>> navigatorKeys;

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBar: CupertinoTabBar(
        items: [
          _buildItem(TabItem.timeline),
          _buildItem(TabItem.map),
          _buildItem(TabItem.share),
          _buildItem(TabItem.account),
        ],
        onTap: (index) => onSelectTab(TabItem.values[index]),
      ),
      tabBuilder: (context, index) {
        final item = TabItem.values[index];
        print(item);

        return CupertinoTabView(
          navigatorKey: navigatorKeys[item],
          builder: (context) => widgetBuilders[item](context),
        );
      },
    );
  }

  BottomNavigationBarItem _buildItem(TabItem tabItem) {
    final itemData = TabItemData.allTabs[tabItem];
    final color = currentTab == tabItem ? Colors.black : Colors.grey;
    return BottomNavigationBarItem(
      icon: Icon(
        itemData.icon,
        color: color,
      ),
      title: Text(
        itemData.title,
        style: TextStyle(color: color),
      ),
    );
  }
}

enum TabItem { timeline, map, share, account }

class TabItemData {
  const TabItemData({@required this.title, @required this.icon});

  final String title;
  final IconData icon;

  static const Map<TabItem, TabItemData> allTabs = {
    TabItem.timeline: TabItemData(title: 'Home', icon: Icons.home),
    TabItem.map: TabItemData(title: 'Map', icon: Icons.pin_drop),
    TabItem.share: TabItemData(title: 'Share', icon: Icons.add_circle_outline),
    TabItem.account: TabItemData(title: 'Account', icon: Icons.person),
  };
}
4

0 回答 0