Flutter页面过渡动画插件beamer的使用

Flutter页面过渡动画插件beamer的使用

简介

Beamer 是一个强大的Flutter导航包,它利用了Router的功能并实现了所有底层逻辑,允许开发者轻松探索任意复杂的导航场景。通过Beamer,你可以实现自定义的页面过渡动画,并且支持嵌套导航、路由保护等功能。

快速开始

导航

要开始使用Beamer进行导航,首先需要设置你的应用程序来使用BeamerDelegateRoutesLocationBuilder。下面是一个简单的例子:

class MyApp extends StatelessWidget {
  final routerDelegate = BeamerDelegate(
    locationBuilder: RoutesLocationBuilder(
      routes: {
        '/': (context, state, data) => HomeScreen(),
        '/books': (context, state, data) => BooksScreen(),
        '/books/:bookId': (context, state, data) {
          final bookId = state.pathParameters['bookId']!;
          final info = (data as MyObject).info;
          return BeamPage(
            key: ValueKey('book-$bookId'),
            title: 'A Book #$bookId',
            popToNamed: '/',
            type: BeamPageType.scaleTransition,
            child: BookDetailsScreen(bookId, info),
          );
        }
      },
    ),
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: BeamerParser(),
      routerDelegate: routerDelegate,
    );
  }
}

在上面的例子中,我们创建了一个包含三个路由的应用程序:根路径(/)、书籍列表页(/books)以及单个书籍详情页(/books/:bookId)。对于书籍详情页,我们还定义了一些额外的行为,如页面键、标题、返回路径等。

返回导航

Beamer 支持两种类型的返回操作:向上(弹出栈顶页面)和逆向时间顺序(回到之前的状态)。可以通过以下方式实现:

  • 向上:使用Navigator.of(context).maybePop()
  • 逆向时间顺序:调用Beamer.of(context).beamBack()

此外,为了确保Android设备上的物理返回按钮能够正常工作,还需要配置BeamerBackButtonDispatcher

MaterialApp.router(
  ...
  routerDelegate: beamerDelegate,
  backButtonDispatcher: BeamerBackButtonDispatcher(delegate: beamerDelegate),
)

获取最近的Beamer实例

有时候你可能需要访问当前上下文中的Beamer实例以获取其状态或执行其他操作。可以这样做:

final beamState = Beamer.of(context).currentBeamLocation.state as BeamState;
final bookId = beamState.pathParameters['bookId'];

示例代码

接下来是完整的示例代码,展示了如何使用Beamer来进行页面之间的切换:

import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:beamer/beamer.dart';

// 数据模型
class Book {
  const Book(this.id, this.title, this.author);

  final int id;
  final String title;
  final String author;
}

const List<Book> books = [
  Book(1, 'Stranger in a Strange Land', 'Robert A. Heinlein'),
  Book(2, 'Foundation', 'Isaac Asimov'),
  Book(3, 'Fahrenheit 451', 'Ray Bradbury'),
];

// 页面组件
class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.beamToNamed('/books'),
          child: const Text('See books'),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Books'),
      ),
      body: ListView(
        children: books
            .map(
              (book) => ListTile(
                title: Text(book.title),
                subtitle: Text(book.author),
                onTap: () => context.beamToNamed('/books/${book.id}'),
              ),
            )
            .toList(),
      ),
    );
  }
}

class BookDetailsScreen extends StatelessWidget {
  const BookDetailsScreen({Key? key, required this.book}) : super(key: key);

  final Book? book;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(book?.title ?? 'Not Found'),
      ),
      body: book != null
          ? Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text('Author: ${book!.author}'),
            )
          : const SizedBox.shrink(),
    );
  }
}

// 定义导航位置
class BooksLocation extends BeamLocation<BeamState> {
  @override
  List<Pattern> get pathPatterns => ['/books/:bookId'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    final pages = [
      const BeamPage(
        key: ValueKey('home'),
        title: 'Home',
        child: HomeScreen(),
      ),
      if (state.uri.pathSegments.contains('books'))
        const BeamPage(
          key: ValueKey('books'),
          title: 'Books',
          child: BooksScreen(),
        ),
    ];
    final String? bookIdParameter = state.pathParameters['bookId'];
    if (bookIdParameter != null) {
      final bookId = int.tryParse(bookIdParameter);
      final book = books.firstWhereOrNull((book) => book.id == bookId);
      pages.add(
        BeamPage(
          key: ValueKey('book-$bookIdParameter'),
          title: 'Book #$bookIdParameter',
          child: BookDetailsScreen(book: book),
        ),
      );
    }
    return pages;
  }
}

// 主应用
class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);

  final routerDelegate = BeamerDelegate(
    locationBuilder: BeamerLocationBuilder(
      beamLocations: [BooksLocation()],
    ),
    notFoundRedirectNamed: '/books',
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: routerDelegate,
      routeInformationParser: BeamerParser(),
      backButtonDispatcher:
          BeamerBackButtonDispatcher(delegate: routerDelegate),
    );
  }
}

void main() => runApp(MyApp());

在这个例子中,我们定义了一个简单的图书管理系统,包括首页、书籍列表页和书籍详情页。通过Beamer提供的API,我们可以轻松地在这几个页面之间进行导航,并且可以根据需要添加自定义的过渡效果和其他功能。


更多关于Flutter页面过渡动画插件beamer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter页面过渡动画插件beamer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用beamer插件来实现页面过渡动画的示例代码。beamer是一个灵活且功能强大的路由和导航库,支持自定义页面过渡动画。

首先,确保你已经在你的pubspec.yaml文件中添加了beamer依赖:

dependencies:
  flutter:
    sdk: flutter
  beamer: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来获取依赖。

接下来,我们将设置Beamer导航,并定义一个简单的页面过渡动画。

主应用文件 main.dart

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Beam(
        initialLocation: '/',
        beamLocations: [
          BeamLocation(
            path: '/',
            title: 'Home',
            beamWidget: HomeScreen(),
          ),
          BeamLocation(
            path: '/details',
            title: 'Details',
            beamWidget: DetailsScreen(),
          ),
        ],
        // 自定义过渡动画
        transitionsBuilder: (context, location, previousLocation, child) {
          if (previousLocation == null) {
            // 从无到有的过渡(如应用启动)
            return SlideTransition(
              position: Tween<Offset>(
                begin: Offset(1.0, 0.0),
                end: Offset.zero,
              ).animate(AnimationController(
                duration: const Duration(milliseconds: 500),
                vsync: Beamer.of(context).vsync,
              )),
              child: child,
            );
          } else if (previousLocation.path == '/' && location.path == '/details') {
            // 从Home到Details的过渡
            return SlideTransition(
              position: Tween<Offset>(
                begin: Offset.zero,
                end: Offset(1.0, 0.0),
              ).animate(AnimationController(
                duration: const Duration(milliseconds: 500),
                vsync: Beamer.of(context).vsync,
              )),
              child: child,
            );
          } else if (previousLocation.path == '/details' && location.path == '/') {
            // 从Details回到Home的过渡
            return SlideTransition(
              position: Tween<Offset>(
                begin: Offset(-1.0, 0.0),
                end: Offset.zero,
              ).animate(AnimationController(
                duration: const Duration(milliseconds: 500),
                vsync: Beamer.of(context).vsync,
              )),
              child: child,
            );
          }
          return child;
        },
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Beamer.of(context).beamToNamed('/details'),
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Details'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Beamer.of(context).beamBack(),
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

解释

  1. Beamer配置:

    • MaterialApphome属性中,我们使用了Beam小部件,它接受initialLocationbeamLocations参数来配置导航路径和页面。
    • transitionsBuilder允许我们定义自定义的过渡动画。我们根据previousLocationlocation来区分不同的导航场景,并应用相应的动画。
  2. 页面定义:

    • HomeScreenDetailsScreen是两个简单的页面,分别包含一个按钮来导航到另一个页面或返回。
  3. 导航:

    • 使用Beamer.of(context).beamToNamed('/details')来导航到详情页面。
    • 使用Beamer.of(context).beamBack()来返回上一个页面。

这个示例展示了如何使用beamer插件来创建带有自定义过渡动画的页面导航。你可以根据需要进一步定制过渡动画和页面结构。

回到顶部