Flutter动画过渡效果插件morpheus的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter动画过渡效果插件morpheus的使用

Morpheus 是一个用于轻松实现 Material Design 导航过渡效果的 Flutter 包。

版本信息

Pub

Actions Status

示例

父子过渡

你可以使用 MorpheusPageRoute 在两个屏幕之间创建一个父子过渡。

import 'package:morpheus/morpheus.dart';

class MyList extends StatelessWidget {

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 10,
      itemBuilder: (context, index) {
        final _parentKey = GlobalKey();
        return ListTile(
          key: _parentKey,
          leading: CircleAvatar(child: Text((index + 1).toString())),
          title: Text('Item ${index + 1}'),
          onTap: () => _handleTap(context, _parentKey),
        );
      }
    );
  }

  void _handleTap(BuildContext context, GlobalKey parentKey) {
    Navigator.of(context).push(MorpheusPageRoute(
      builder: (context) => Scaffold(),
      parentKey: parentKey,
    ));
  }

}

顶级过渡

你可以使用 MorpheusTabView 小部件在子小部件更改时创建顶级过渡。

import 'package:morpheus/morpheus.dart';

class MyTabScreen extends StatefulWidget {

  [@override](/user/override)
  _MyTabScreenState createState() => _MyTabScreenState();

}

class _MyTabScreenState extends State<MyTabScreen> {

  final List<Widget> _screens = [
    Scaffold(backgroundColor: Colors.green),
    Scaffold(backgroundColor: Colors.red),
    Scaffold(backgroundColor: Colors.blue),
  ];
  int _currentIndex = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: MorpheusTabView(
        child: _screens[_currentIndex]
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.trending_up),
            title: Text('Trending'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.star),
            title: Text('Saved'),
          ),
        ],
        onTap: (index) {
          if (index != _currentIndex) {
            setState(() => _currentIndex = index);
          }
        },
      ),
    );
  }

}

完整示例

以下是一个完整的示例,展示了如何在 Flutter 应用程序中使用 Morpheus 插件来实现复杂的导航过渡效果。

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    const colorScheme = ColorScheme.light();
    return MaterialApp(
      theme: ThemeData(
        colorScheme: colorScheme,
        primaryColor: colorScheme.primary,
        scaffoldBackgroundColor: colorScheme.background,
      ),
      title: 'Morpheus example app',
      onGenerateRoute: (settings) {
        switch (settings.name) {
          case '/profile':
            return MorpheusPageRoute(
              builder: (_) => const ProfileScreen(),
              settings: settings,
            );
          case '/settings':
            return MorpheusPageRoute(
              builder: (_) => SettingsScreen(),
              settings: settings,
            );
          case '/settings/cookies':
            return MorpheusPageRoute(
              builder: (_) => const CookiesScreen(),
              settings: settings,
            );
          case '/create':
            return MorpheusPageRoute(
              builder: (_) => const CreateScreen(),
              settings: settings,
            );
          case '/':
          default:
            return MorpheusPageRoute(
              builder: (_) => const HomeScreen(),
              settings: settings,
            );
        }
      },
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  [@override](/user/override)
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final profileKey = GlobalKey();
  final settingsKey = GlobalKey();
  final createKey = GlobalKey();
  int _currentIndex = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: MorpheusTabView(
        child: [
          const ProfileScreen(
            key: Key('profile'),
          ),
          SettingsScreen(
            key: const Key('settings'),
          ),
        ][_currentIndex],
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton.extended(
        key: createKey,
        icon: const Icon(Icons.add),
        label: const Text('Create'),
        onPressed: () => Navigator.of(context).pushNamed(
          '/create',
          arguments: MorpheusRouteArguments(
            parentKey: createKey,
            transitionColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
            borderRadius: BorderRadius.circular(24.0),
          ),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) => setState(() => _currentIndex = index),
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.account_circle),
            label: 'Profile',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
    );
  }
}

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

  final cookiesKey = GlobalKey();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Settings'),
      ),
      body: ListView(
        children: [
          ListTile(
            key: cookiesKey,
            title: const Text('Cookies'),
            onTap: () => Navigator.of(context).pushNamed(
              '/settings/cookies',
              arguments: MorpheusRouteArguments(
                parentKey: cookiesKey,
              ),
            ),
          ),
          const Divider(height: 1.0),
        ],
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            title: Text('Create'),
            expandedHeight: 224.0,
          ),
        ],
      ),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            title: Text('Cookies'),
            expandedHeight: 224.0,
          ),
        ],
      ),
    );
  }
}

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

1 回复

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


当然,下面是一个关于如何在Flutter中使用morpheus插件来实现动画过渡效果的代码案例。morpheus插件提供了一系列高级的过渡动画,使得开发者可以轻松地为Flutter应用添加复杂的动画效果。

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

dependencies:
  flutter:
    sdk: flutter
  morpheus: ^0.3.2  # 请确保版本号是最新的

然后,运行flutter pub get来安装依赖。

接下来,我们来看一个具体的代码示例,展示如何在两个页面之间使用Morpheus动画进行过渡。

主应用代码 (main.dart)

import 'package:flutter/material.dart';
import 'package:morpheus/morpheus.dart';
import 'second_screen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Morpheus Animation Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Morpheus Animation Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MorpheusPageRoute(
                builder: (context) => SecondScreen(),
                animationType: MorpheusAnimationType.FADE_IN_UP,
              ),
            );
          },
          child: Text('Go to Second Screen'),
        ),
      ),
    );
  }
}

第二个屏幕代码 (second_screen.dart)

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

自定义路由 (morpheus_page_route.dart)

由于morpheus插件并不直接提供一个MorpheusPageRoute,这里我们需要自己实现一个自定义路由类来使用Morpheus动画。下面是一个简单的实现:

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

class MorpheusPageRoute<T> extends PageRoute<T> {
  final WidgetBuilder builder;
  final MorpheusAnimationType animationType;

  MorpheusPageRoute({
    required this.builder,
    required this.animationType,
    RouteSettings? settings,
  }) : super(settings: settings);

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    return Material(
      child: Morpheus(
        animationType: animationType,
        child: builder(context),
      ),
    );
  }

  @override
  bool get maintainState => true;

  @override
  Duration get transitionDuration => Duration(milliseconds: 700);

  @override
  Color? get barrierColor => null;

  @override
  String? get barrierLabel => null;
}

在这个例子中,我们创建了一个MorpheusPageRoute类,它接受一个builder函数和一个animationType。这个路由类使用Morpheus小部件来包装页面内容,并应用指定的动画类型。

运行效果

当你点击主屏幕上的按钮时,应用会使用MorpheusAnimationType.FADE_IN_UP动画将第二个屏幕推入视图。返回时,由于没有特别处理返回动画,它会使用默认的返回动画。你可以根据需要为返回动画也实现一个自定义的过渡效果。

希望这个示例能帮助你理解如何在Flutter中使用morpheus插件来实现动画过渡效果。

回到顶部