0

我正在尝试使用新的 Material You API 来实现 NavigationBar。

https://api.flutter.dev/flutter/material/NavigationBar-class.html

我只是想知道我们是否可以使用 Go_Router 包实现相同的功能。

4

1 回答 1

0

对的,这是可能的。

让我们以 GoRouter 文档中的示例为起点。

  1. 我们需要创建一些基本模型来存储数据:
/// Just a generic model that will be used to present some data on the screen.
class Person {
  final String id;
  final String name;

  Person({required this.id, required this.name});
}

/// Family will be the model that represents our tabs. We use the properties `icon` and `name` in the `NavigationBar`.
class Family {
  final String id;
  final String name;
  final List<Person> people;
  final Icon icon;

  Family({
    required this.id,
    required this.name,
    required this.people,
    required this.icon,
  });
}

/// Families will be used to store the tabs to be easily accessed anywhere. In a real application you would use something fancier.
class Families {
  static const List<Icon> icons = [
    Icon(Icons.looks_one),
    Icon(Icons.looks_two),
    Icon(Icons.looks_3)
  ];

  static final List<Family> data = List.generate(
    3,
    (fid) => Family(
      id: '$fid',
      name: 'Family $fid',
      people: List.generate(
        10,
        (id) => Person(id: '$id', name: 'Family $fid Person $id'),
      ),
      icon: icons[fid],
    ),
  );
}
  1. 现在我们将创建将呈现模型数据的基本视图:
/// Used to present Person's data.
class PersonView extends StatelessWidget {
  const PersonView({required this.person, Key? key}) : super(key: key);
  final Person person;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text(person.name),
      ),
    );
  }
}

/// This is the view that will be used by each application's tab.
class FamilyView extends StatefulWidget {
  const FamilyView({required this.family, Key? key}) : super(key: key);
  final Family family;

  @override
  State<FamilyView> createState() => _FamilyViewState();
}


class _FamilyViewState extends State<FamilyView>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return ListView(
      children: [
        for (final p in widget.family.people)
          ListTile(
            title: Text(p.name),
            onTap: () =>
                context.go('/family/${widget.family.id}/person/${p.id}'),
          ),
      ],
    );
  }
}

  1. 到目前为止,与GoRouter文档相比,我们没有做任何不同的事情,所以让我们最终创建将显示的小部件NavigationBar
class FamilyTabsScreen extends StatefulWidget {
  final int index;
  FamilyTabsScreen({required Family currentFamily, Key? key})
      : index = Families.data.indexWhere((f) => f.id == currentFamily.id),
        super(key: key) {
    assert(index != -1);
  }

  @override
  _FamilyTabsScreenState createState() => _FamilyTabsScreenState();
}

class _FamilyTabsScreenState extends State<FamilyTabsScreen>
    with TickerProviderStateMixin {
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(_title(context)),
        ),
        body: FamilyView(family: Families.data[widget.index]),
        bottomNavigationBar: NavigationBar(
          destinations: [
            for (final f in Families.data)
              NavigationDestination(
                icon: f.icon,
                label: f.name,
              )
          ],
          onDestinationSelected: (index) => _tap(context, index),
          selectedIndex: widget.index,
        ),
      );

  void _tap(BuildContext context, int index) =>
      context.go('/family/${Families.data[index].id}');

  String _title(BuildContext context) =>
      (context as Element).findAncestorWidgetOfExactType<MaterialApp>()!.title;
}

这是上面代码的重要部分:

/// [...] suppressed code
bottomNavigationBar: NavigationBar(
  destinations: [
    for (final f in Families.data)
      NavigationDestination(
        icon: f.icon,
        label: f.name,
      )
  ],
  onDestinationSelected: (index) => _tap(context, index),
  selectedIndex: widget.index,
),
/// [...] suppressed code

所以,基本上我们使用的NavigationBar几乎与使用TabBarView.

  1. 最后,这只有在我们定义应用程序的路由并将 设置GoRouter为应用程序的导航器时才有效:

void main() {
  GoRouter.setUrlPathStrategy(UrlPathStrategy.path);
  runApp(const MyApp());
}

final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      redirect: (_) => '/family/${Families.data[0].id}',
    ),
    GoRoute(
        path: '/family/:fid',
        builder: (context, state) {
          final fid = state.params['fid']!;
          final family = Families.data.firstWhere((f) => f.id == fid,
              orElse: () => throw Exception('family not found: $fid'));

          return FamilyTabsScreen(key: state.pageKey, currentFamily: family);
        },
        routes: [
          GoRoute(
            path: 'person/:id',
            builder: (context, state) {
              final fid = state.params['fid']!;
              final id = state.params['id'];

              final person = Families.data
                  .firstWhere((f) => f.id == fid,
                      orElse: () => throw Exception('family not found: $fid'))
                  .people
                  .firstWhere(
                    ((p) => p.id == id),
                    orElse: () => throw Exception('person not found: $id'),
                  );

              return PersonView(key: state.pageKey, person: person);
            },
          ),
        ]),
  ],
);

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Flutter Demo',
      routeInformationParser: _router.routeInformationParser,
      routerDelegate: _router.routerDelegate,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}

通过所有这些步骤,您将拥有:

在此处输入图像描述

于 2022-02-05T15:05:22.400 回答