Flutter页面过渡动画插件beamer的使用
Flutter页面过渡动画插件beamer的使用
简介
Beamer 是一个强大的Flutter导航包,它利用了Router
的功能并实现了所有底层逻辑,允许开发者轻松探索任意复杂的导航场景。通过Beamer,你可以实现自定义的页面过渡动画,并且支持嵌套导航、路由保护等功能。
快速开始
导航
要开始使用Beamer进行导航,首先需要设置你的应用程序来使用BeamerDelegate
和RoutesLocationBuilder
。下面是一个简单的例子:
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
更多关于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'),
),
),
);
}
}
解释
-
Beamer配置:
- 在
MaterialApp
的home
属性中,我们使用了Beam
小部件,它接受initialLocation
和beamLocations
参数来配置导航路径和页面。 transitionsBuilder
允许我们定义自定义的过渡动画。我们根据previousLocation
和location
来区分不同的导航场景,并应用相应的动画。
- 在
-
页面定义:
HomeScreen
和DetailsScreen
是两个简单的页面,分别包含一个按钮来导航到另一个页面或返回。
-
导航:
- 使用
Beamer.of(context).beamToNamed('/details')
来导航到详情页面。 - 使用
Beamer.of(context).beamBack()
来返回上一个页面。
- 使用
这个示例展示了如何使用beamer
插件来创建带有自定义过渡动画的页面导航。你可以根据需要进一步定制过渡动画和页面结构。