Flutter动画导航栏插件animated_navbar的使用
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 回复