Flutter动画导航栏插件animated_navbar的使用

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

Flutter动画导航栏插件animated_navbar的使用

特性

  • 动画导航栏

开始使用

首先,导入相关的库。

import 'package:animated_notched_navbar/animated_notched_navbar';

使用方法

以下是一个完整的示例代码,展示了如何使用 animated_notched_navbar 插件创建一个带有动画效果的导航栏。

import 'dart:math' as math;
import 'package:flutter/material.dart';

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

// 主应用小部件
class MyHome extends StatelessWidget {
  const MyHome({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: NavPackage(),
    );
  }
}

// 导航栏小部件
class NavPackage extends StatefulWidget {
  const NavPackage({super.key});

  [@override](/user/override)
  State<NavPackage> createState() => _NavPackageState();
}

class _NavPackageState extends State<NavPackage> with TickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;

  bool isHovered = false;

  [@override](/user/override)
  void initState() {
    super.initState();

    // 动画控制器用于旋转FloatingActionButton
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800),
    );

    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: _animationController,
        curve: Curves.easeInOut,
      ),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return Scaffold(
      body: Stack(
        children: [
          Positioned(
            bottom: 0,
            left: 0,
            child: SizedBox(
              width: size.width,
              height: 80,
              child: Stack(
                children: [
                  // 自定义绘制器绘制装饰形状
                  CustomPaint(
                    size: Size(size.width, 80),
                    painter: MyPainter(),
                  ),
                  Center(
                    heightFactor: 0.6,
                    child: MouseRegion(
                      // 处理FloatingActionButton的鼠标悬停事件
                      onEnter: (_) {
                        _animationController.forward();
                        setState(() {
                          isHovered = true;
                        });
                      },
                      onExit: (_) {
                        _animationController.reverse();
                        setState(() {
                          isHovered = false;
                        });
                      },
                      child: AnimatedBuilder(
                        // 应用旋转动画到FloatingActionButton
                        animation: _animation,
                        builder: (context, child) {
                          return Transform.rotate(
                            angle: isHovered ? _animation.value * 0.80 : 0.0,
                            child: FloatingActionButton(
                              onPressed: () {
                                _animationController.forward();
                              },
                              backgroundColor: isHovered
                                  ? Colors.orange.withOpacity(_animation.value)
                                  : Colors.yellow,
                              child: const Icon(Icons.add),
                            ),
                          );
                        },
                      ),
                    ),
                  ),
                  SizedBox(
                    width: size.width,
                    height: 80,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        // 带有悬停效果的自定义IconButton
                        HoverIconButton(
                          onPressed: () {},
                          icon: const Icon(Icons.home),
                          animationController: _animationController,
                        ),
                        HoverIconButton(
                          onPressed: () {},
                          icon: const Icon(Icons.book_online),
                          animationController: _animationController,
                        ),
                        Container(
                          width: size.width * 0.20,
                        ),
                        HoverIconButton(
                          onPressed: () {},
                          icon: const Icon(Icons.carpenter),
                          animationController: _animationController,
                        ),
                        HoverIconButton(
                          onPressed: () {},
                          icon: const Icon(Icons.shop),
                          animationController: _animationController,
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// 带有悬停效果的自定义IconButton
class HoverIconButton extends StatefulWidget {
  final VoidCallback onPressed;
  final Icon icon;
  final AnimationController animationController;

  const HoverIconButton({
    super.key,
    required this.onPressed,
    required this.icon,
    required this.animationController,
  });

  [@override](/user/override)
  // ignore: library_private_types_in_public_api
  _HoverIconButtonState createState() => _HoverIconButtonState();
}

class _HoverIconButtonState extends State<HoverIconButton> {
  bool isHovered = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MouseRegion(
      // 处理IconButton的鼠标悬停事件
      onEnter: (_) {
        widget.animationController.forward();
        setState(() {
          isHovered = true;
        });
      },
      onExit: (_) {
        widget.animationController.reverse();
        setState(() {
          isHovered = false;
        });
      },
      child: IconButton(
        onPressed: widget.onPressed,
        icon: AnimatedSwitcher(
          duration: const Duration(milliseconds: 300),
          child: isHovered
              ? Icon(
                  widget.icon.icon,
                  size: 50,
                  color: const Color.fromARGB(255, 9, 9, 9),
                )
              : Icon(
                  widget.icon.icon,
                  size: 24,
                ),
        ),
      ),
    );
  }
}

// 自定义绘制器用于绘制带有滴落效果的装饰形状
class MyPainter extends CustomPainter {
  [@override](/user/override)
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.yellow
      ..style = PaintingStyle.fill;

    Path path = Path()..moveTo(0, 20);
    path.quadraticBezierTo(size.width * 0.20, 0, size.width * 0.40, 0);
    path.quadraticBezierTo(size.width * 0.40, 10, size.width * 0.40, 20);

    path.arcToPoint(Offset(size.width * 0.60, 20),
        radius: const Radius.circular(10.0), clockwise: false);

    path.quadraticBezierTo(size.width * 0.60, 0, size.width * 0.60, 0);
    path.quadraticBezierTo(size.width * 0.80, 0, size.width, 20);

    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);

    path.close();

    canvas.drawShadow(path, Colors.yellow, 5, true);
    canvas.drawPath(path, paint);

    // 绘制滴落效果
    if (path.contains(Offset(size.width * 0.50, 20))) {
      double dripHeight = 60;
      double dripWidth = 10;
      double gap = 10;

      for (double i = 0; i < dripHeight; i += gap) {
        double x = size.width * 0.50 - dripWidth / 2;
        double y = 20 + i;
        double endY = math.min(y + gap, size.height - 80);

        canvas.drawLine(
          Offset(x, y),
          Offset(x, endY),
          paint..color = Colors.orange.withOpacity(0.5),
        );
      }
    }
  }

  [@override](/user/override)
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

更多关于Flutter动画导航栏插件animated_navbar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画导航栏插件animated_navbar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用animated_navbar插件的示例代码。这个插件允许你创建一个带有动画效果的导航栏。

首先,你需要在你的pubspec.yaml文件中添加animated_navbar依赖:

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

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

接下来,我们可以创建一个简单的Flutter应用,展示如何使用animated_navbar

主应用文件 (main.dart)

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animated NavBar Example'),
      ),
      body: Column(
        children: [
          AnimatedNavBar(
            controller: _controller,
            items: [
              NavBarItem(
                icon: Icons.home,
                label: 'Home',
              ),
              NavBarItem(
                icon: Icons.search,
                label: 'Search',
              ),
              NavBarItem(
                icon: Icons.account_circle,
                label: 'Profile',
              ),
            ],
            onItemSelected: (index) {
              // 导航到不同的页面或执行其他操作
              print('Selected item: $index');
            },
          ),
          Expanded(
            child: Center(
              child: AnimatedBuilder(
                animation: _controller,
                child: Text('Home'),
                builder: (context, child) {
                  return Transform.translate(
                    offset: Offset(
                      _controller.value * 100.0,
                      0.0,
                    ),
                    child: child,
                  );
                },
              ),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_controller.isAnimating) {
            _controller.stop();
          } else {
            _controller.reverse() ?? _controller.forward();
          }
        },
        tooltip: 'Toggle NavBar',
        child: Icon(Icons.arrow_downward),
      ),
    );
  }
}

说明

  1. 依赖添加:在pubspec.yaml中添加animated_navbar依赖。
  2. 主应用文件
    • 使用MaterialApp来设置主应用。
    • HomeScreen是一个有状态的Widget,它包含一个AnimatedNavBar和一个AnimationController
    • AnimatedNavBar接受一个controller(用于动画效果)和一个items列表(包含导航栏的图标和标签)。
    • onItemSelected回调会在用户点击导航栏项时被调用。
    • AnimatedBuilder用于根据_controller的值来动画化一个子Widget(在这个例子中是一个简单的文本)。
    • 一个FloatingActionButton用于触发动画(在这个例子中只是简单地反转或启动动画)。

注意:

  • animated_navbar插件的实际API和用法可能会有所不同,请根据你使用的版本查阅官方文档。
  • 示例代码中的动画效果仅为演示目的,实际应用中你可能需要根据需求进行调整。

希望这个示例能帮助你理解如何在Flutter项目中使用animated_navbar插件。

回到顶部