首页小e动画
This commit is contained in:
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 6.9 KiB |
273
lib/pages/mh_page/FloatingSvgIcon.dart
Normal file
273
lib/pages/mh_page/FloatingSvgIcon.dart
Normal file
@@ -0,0 +1,273 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
// class FloatingSvgIcon extends StatefulWidget {
|
||||
// final String assetPath; // SVG 图标路径
|
||||
// final double width; // 宽度
|
||||
// final double height; // 高度
|
||||
// final Duration duration; // 浮动周期
|
||||
// final double floatOffset; // 浮动高度(单位:比例)
|
||||
// final VoidCallback? onTap; // 点击事件
|
||||
|
||||
// const FloatingSvgIcon({
|
||||
// super.key,
|
||||
// required this.assetPath,
|
||||
// this.width = 60,
|
||||
// this.height = 60,
|
||||
// this.duration = const Duration(milliseconds: 800),
|
||||
// this.floatOffset = 0.02,
|
||||
// this.onTap,
|
||||
// });
|
||||
|
||||
// @override
|
||||
// State<FloatingSvgIcon> createState() => _FloatingSvgIconState();
|
||||
// }
|
||||
|
||||
// class _FloatingSvgIconState extends State<FloatingSvgIcon>
|
||||
// with SingleTickerProviderStateMixin {
|
||||
// late final AnimationController _controller;
|
||||
// late final Animation<Offset> _animation;
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
|
||||
// _controller = AnimationController(
|
||||
// vsync: this,
|
||||
// duration: widget.duration,
|
||||
// )..repeat(reverse: true);
|
||||
|
||||
// _animation = Tween<Offset>(
|
||||
// begin: Offset(0, -widget.floatOffset),
|
||||
// end: Offset(0, widget.floatOffset),
|
||||
// ).animate(CurvedAnimation(
|
||||
// parent: _controller,
|
||||
// curve: Curves.easeInOut,
|
||||
// ));
|
||||
// }
|
||||
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _controller.dispose();
|
||||
// super.dispose();
|
||||
// }
|
||||
|
||||
// // 计算阴影缩放因子,范围大致从 0.8 ~ 1.2
|
||||
// double getShadowScale(double dy) {
|
||||
// return 1 - dy * 0.25; // dy 为负时,scale > 1,dy 为正时,scale < 1
|
||||
// }
|
||||
|
||||
// // 计算阴影透明度,范围大致从 0.3 ~ 0.7
|
||||
// double getShadowOpacity(double dy) {
|
||||
// return 0.5 - dy * 0.3;
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return AnimatedBuilder(
|
||||
// animation: _controller,
|
||||
// builder: (context, child) {
|
||||
// final dy = _animation.value.dy;
|
||||
|
||||
// final shadowScale = getShadowScale(dy).clamp(0.8, 1.2);
|
||||
// final shadowOpacity = getShadowOpacity(dy).clamp(0.3, 0.7);
|
||||
|
||||
// return SlideTransition(
|
||||
// position: _animation,
|
||||
// child: GestureDetector(
|
||||
// onTap: widget.onTap,
|
||||
// child: SizedBox(
|
||||
// width: widget.width,
|
||||
// height: widget.height + widget.height * 0.3, // 多留点高度给阴影
|
||||
// child: Stack(
|
||||
// alignment: Alignment.topCenter,
|
||||
// children: [
|
||||
// // 阴影在底部,椭圆形,随浮动缩放和透明度变化
|
||||
// Positioned(
|
||||
// bottom: 0,
|
||||
// child: Transform.scale(
|
||||
// scale: shadowScale,
|
||||
// child: Opacity(
|
||||
// opacity: shadowOpacity,
|
||||
// child: Container(
|
||||
// width: widget.width * 0.6,
|
||||
// height: widget.height * 0.08,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.black54,
|
||||
// borderRadius:
|
||||
// BorderRadius.circular(widget.height * 0.075),
|
||||
// boxShadow: [
|
||||
// BoxShadow(
|
||||
// color: Colors.black26,
|
||||
// blurRadius: 8,
|
||||
// spreadRadius: 1,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
// // SVG图标
|
||||
// Positioned(
|
||||
// top: 0,
|
||||
// child: SizedBox(
|
||||
// width: widget.width,
|
||||
// height: widget.height,
|
||||
// child: SvgPicture.asset(
|
||||
// widget.assetPath,
|
||||
// fit: BoxFit.fill,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class FloatingSvgIcon extends StatefulWidget {
|
||||
final String assetPath; // SVG 图标路径
|
||||
final double width; // 宽度
|
||||
final double height; // 高度
|
||||
final Duration duration; // 浮动周期
|
||||
final double floatOffset; // 浮动高度(单位:比例)
|
||||
final VoidCallback? onTap; // 点击事件
|
||||
|
||||
const FloatingSvgIcon({
|
||||
super.key,
|
||||
required this.assetPath,
|
||||
this.width = 60,
|
||||
this.height = 60,
|
||||
this.duration = const Duration(milliseconds: 800),
|
||||
this.floatOffset = 0.02,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
State<FloatingSvgIcon> createState() => _FloatingSvgIconState();
|
||||
}
|
||||
|
||||
class _FloatingSvgIconState extends State<FloatingSvgIcon>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final AnimationController _controller;
|
||||
late final Animation<Offset> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: widget.duration,
|
||||
)..repeat(reverse: true);
|
||||
|
||||
_animation = Tween<Offset>(
|
||||
begin: Offset(0, -widget.floatOffset),
|
||||
end: Offset(0, widget.floatOffset),
|
||||
).animate(CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// // 计算阴影缩放因子,范围大致从 0.8 ~ 1.2
|
||||
// double getShadowScale(double dy) {
|
||||
// // dy 是当前偏移,负表示向上,正表示向下
|
||||
// // 上浮时阴影变小,下落时阴影变大
|
||||
// return (1 - dy * 5).clamp(0.8, 1.2);
|
||||
// }
|
||||
|
||||
// // 计算阴影透明度,范围大致从 0.3 ~ 0.7
|
||||
// double getShadowOpacity(double dy) {
|
||||
// return (0.5 - dy * 1.5).clamp(0.3, 0.7);
|
||||
// }
|
||||
double getShadowScale(double dy) {
|
||||
// dy负时(上浮)阴影变小,正时(下落)阴影变大
|
||||
return (1 + dy * 5).clamp(0.8, 1.2);
|
||||
}
|
||||
|
||||
double getShadowOpacity(double dy) {
|
||||
return (0.5 + dy * 1.5).clamp(0.3, 0.7);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) {
|
||||
final dy = _animation.value.dy;
|
||||
|
||||
final shadowScale = getShadowScale(dy);
|
||||
final shadowOpacity = getShadowOpacity(dy);
|
||||
|
||||
return SizedBox(
|
||||
width: widget.width,
|
||||
height: widget.height + widget.height * 0.3, // 留出阴影空间
|
||||
child: Stack(
|
||||
alignment: Alignment.topCenter,
|
||||
children: [
|
||||
// 固定底部投影,大小随动画变化
|
||||
Positioned(
|
||||
bottom: 4,
|
||||
child: Transform.scale(
|
||||
scale: shadowScale,
|
||||
child: Opacity(
|
||||
opacity: shadowOpacity,
|
||||
child: Container(
|
||||
width: widget.width * 0.5,
|
||||
height: widget.height * 0.12,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
borderRadius:
|
||||
BorderRadius.circular(widget.height * 0.1),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black38,
|
||||
blurRadius: 12,
|
||||
spreadRadius: 0,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// SVG图标上下浮动
|
||||
SlideTransition(
|
||||
position: _animation,
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: SizedBox(
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
child: SvgPicture.asset(
|
||||
widget.assetPath,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||
import 'package:vbvs_app/controller/mh_controller/muser_info_controller.dart';
|
||||
|
||||
import 'package:vbvs_app/pages/mh_page/FloatingSvgIcon.dart';
|
||||
|
||||
class NewHomePage extends StatefulWidget {
|
||||
const NewHomePage({super.key});
|
||||
@@ -96,11 +96,14 @@ class _NewHomePageState extends State<NewHomePage> {
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: AppBar(
|
||||
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||
iconTheme:
|
||||
IconThemeData(color: themeController.currentColor.sc3),
|
||||
backgroundColor: Colors.transparent,
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 0,
|
||||
title: Row(
|
||||
title: Container(
|
||||
height: 180.rpx,
|
||||
child: Row(
|
||||
children: [
|
||||
// 左侧头像
|
||||
SizedBox(width: 40.rpx),
|
||||
@@ -108,7 +111,8 @@ class _NewHomePageState extends State<NewHomePage> {
|
||||
radius: 27.rpx, // 可根据需求调整
|
||||
backgroundImage: login == 1
|
||||
? (userInfoController.model.user!.avatar == null ||
|
||||
userInfoController.model.user!.avatar!.isEmpty
|
||||
userInfoController
|
||||
.model.user!.avatar!.isEmpty
|
||||
? const AssetImage(
|
||||
"assets/images/people_avatar.png",
|
||||
)
|
||||
@@ -136,24 +140,20 @@ class _NewHomePageState extends State<NewHomePage> {
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(width: 46.rpx), // icon 之间的间距
|
||||
ClickableContainer(
|
||||
backgroundColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
padding: EdgeInsets.only(right: 0),
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
height: 60.rpx,
|
||||
width: 75.rpx,
|
||||
child: SvgPicture.asset(
|
||||
'assets/img/icon/xiaoe.svg',
|
||||
// color: Colors.white,
|
||||
))),
|
||||
|
||||
// SizedBox(width: 40.rpx),
|
||||
FloatingSvgIcon(
|
||||
assetPath: 'assets/img/icon/xiaoe.svg',
|
||||
width: 60.rpx,
|
||||
height: 60.rpx,
|
||||
onTap: () {
|
||||
print("点击了小鹅图标");
|
||||
},
|
||||
),
|
||||
|
||||
SizedBox(width: 40.rpx),
|
||||
],
|
||||
),
|
||||
centerTitle: false,
|
||||
),
|
||||
)),
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
@@ -165,9 +165,7 @@ class _NewHomePageState extends State<NewHomePage> {
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ),
|
||||
decoration: BoxDecoration(
|
||||
|
||||
),
|
||||
decoration: BoxDecoration(),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
||||
Reference in New Issue
Block a user