优化动画效果

This commit is contained in:
yuanjunyao 2023-11-30 10:16:09 +08:00
parent e24be85f04
commit d950901497
6 changed files with 214 additions and 103 deletions

View File

@ -66,6 +66,7 @@ class FirstTimeDialog extends StatelessWidget {
left: 0, left: 0,
right: 0, right: 0,
child: AnimatedVisibilityWidget( child: AnimatedVisibilityWidget(
animationWidgetBuilder: AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isVisible: isTextShown.value, isVisible: isTextShown.value,
child: const Center( child: const Center(
child: TouchHintWidget(), child: TouchHintWidget(),

View File

@ -68,6 +68,15 @@ class SelectController extends GetxController {
occupations.add(Occupation( occupations.add(Occupation(
id: 4, id: 4,
gender: 2, gender: 2,
name: '运动员',
enName: 'athletes',
vImage: 'btn_male_pic_athletes',
hImage: 'pic_male_athletes',
selected: false,
));
occupations.add(Occupation(
id: 5,
gender: 2,
name: '画家', name: '画家',
enName: 'artist', enName: 'artist',
vImage: 'btn_male_pic_artist', vImage: 'btn_male_pic_artist',
@ -75,16 +84,6 @@ class SelectController extends GetxController {
selected: true, selected: true,
enable: true, enable: true,
)); ));
occupations.add(Occupation(
id: 5,
gender: 2,
name: '运动员',
enName: 'athletes',
vImage: 'btn_male_pic_athletes',
hImage: 'pic_male_athletes',
selected: false,
));
occupations.add(Occupation( occupations.add(Occupation(
id: 6, id: 6,
gender: 2, gender: 2,

View File

@ -168,6 +168,10 @@ class PartnerWidget extends HookWidget {
return HookBuilder(builder: (context) { return HookBuilder(builder: (context) {
final isDialogShown = useState(false); final isDialogShown = useState(false);
final isTextShown = useState(false); final isTextShown = useState(false);
final fadeOutAnimationController = useAnimationController(
initialValue: 1.0,
duration: const Duration(milliseconds: 500),
);
return Stack( return Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
@ -180,10 +184,19 @@ class PartnerWidget extends HookWidget {
), ),
), ),
), ),
Positioned(top: 42.h, left: 149.w, child: Images.ip), Positioned(
top: 42.h,
left: 149.w,
child: FadeTransition(
opacity: fadeOutAnimationController,
child: Images.ip,
),
),
Positioned( Positioned(
top: 76.h, top: 76.h,
left: 451.w, left: 451.w,
child: FadeTransition(
opacity: fadeOutAnimationController,
child: AnimatedVisibilityWidget( child: AnimatedVisibilityWidget(
isVisible: true, isVisible: true,
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
@ -216,6 +229,7 @@ class PartnerWidget extends HookWidget {
visible: isDialogShown.value, visible: isDialogShown.value,
child: AnimatedTextKit( child: AnimatedTextKit(
totalRepeatCount: 1, totalRepeatCount: 1,
pause: Duration.zero,
animatedTexts: [ animatedTexts: [
TypewriterAnimatedText( TypewriterAnimatedText(
'每个来到建木之境的探梦者,都需要先选定自己的【梦想职业】,才能继续探索哦。准备好了吗?', '每个来到建木之境的探梦者,都需要先选定自己的【梦想职业】,才能继续探索哦。准备好了吗?',
@ -248,6 +262,7 @@ class PartnerWidget extends HookWidget {
height: 54.0, height: 54.0,
onPressed: () async { onPressed: () async {
await controller.confirm(); await controller.confirm();
await fadeOutAnimationController.reverse();
await Get.offAllNamed(Routes.SELECT); await Get.offAllNamed(Routes.SELECT);
}, },
), ),
@ -260,6 +275,7 @@ class PartnerWidget extends HookWidget {
), ),
), ),
), ),
),
], ],
); );
}); });

View File

@ -41,6 +41,7 @@ class WelcomeView extends GetView<WelcomeController> {
: AnimatedVisibilityWidget( : AnimatedVisibilityWidget(
isVisible: !finishInput.value, isVisible: !finishInput.value,
duration: const Duration(milliseconds: 800), duration: const Duration(milliseconds: 800),
curve: Curves.fastOutSlowIn,
animationWidgetBuilder: AnimatedVisibilityWidget animationWidgetBuilder: AnimatedVisibilityWidget
.fadeAnimationWidgetBuilder, .fadeAnimationWidgetBuilder,
onDone: (visible) { onDone: (visible) {

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../utils/image_utils.dart'; import '../utils/image_utils.dart';
@ -17,10 +18,13 @@ class Images {
width: 35.w, width: 35.w,
); );
static Widget up = LoadAssetImage( static Widget up = _UpAndDown(
child: LoadAssetImage(
'btn_icon_up', 'btn_icon_up',
fit: BoxFit.contain,
height: 47.w, height: 47.w,
width: 47.w, width: 47.w,
),
); );
static Widget ip = LoadAssetImage( static Widget ip = LoadAssetImage(
@ -43,16 +47,20 @@ class Images {
fit: BoxFit.fill, fit: BoxFit.fill,
); );
static Widget splashBegin = LoadAssetImage( static Widget splashBegin = _FadeInAndOut(
child: LoadAssetImage(
'splash/btn_icon_begin', 'splash/btn_icon_begin',
height: 105.h, height: 105.h,
width: 378.w, width: 378.w,
),
); );
static Widget welcomeBegin = LoadAssetImage( static Widget welcomeBegin = _FadeInAndOut(
child: LoadAssetImage(
'welcome/btn_label_bg_up', 'welcome/btn_label_bg_up',
height: 114.h, height: 114.h,
width: 270.w, width: 270.w,
),
); );
static Widget pullDown = LoadAssetImage( static Widget pullDown = LoadAssetImage(
@ -61,10 +69,12 @@ class Images {
width: 21.w, width: 21.w,
); );
static Widget pullUp = LoadAssetImage( static Widget pullUp = _UpAndDown(
child: LoadAssetImage(
'welcome/btn_icon_up', 'welcome/btn_icon_up',
height: 21.w, height: 21.w,
width: 21.w, width: 21.w,
),
); );
static Widget selectPre = LoadAssetImage( static Widget selectPre = LoadAssetImage(
@ -79,16 +89,20 @@ class Images {
width: 24.w, width: 24.w,
); );
static Widget questionRecommended = LoadAssetImage( static Widget questionRecommended = _FadeInAndOut(
child: LoadAssetImage(
'question/label_recommended', 'question/label_recommended',
height: 105.h, height: 105.h,
width: 390.w, width: 390.w,
),
); );
static Widget homeCreate = LoadAssetImage( static Widget homeCreate = _FadeInAndOut(
child: LoadAssetImage(
'home/label_label_create', 'home/label_label_create',
height: 105.h, height: 105.h,
width: 378.w, width: 378.w,
),
); );
static Widget homeReset = LoadAssetImage( static Widget homeReset = LoadAssetImage(
@ -319,3 +333,83 @@ class Images {
static const AssetImage avatarUser = static const AssetImage avatarUser =
AssetImage("assets/images/label_avatar_user.png"); AssetImage("assets/images/label_avatar_user.png");
} }
class _FadeInAndOut extends HookWidget {
const _FadeInAndOut({
super.key,
required this.child,
});
final Widget child;
@override
Widget build(BuildContext context) {
final controller = useAnimationController(
duration: const Duration(milliseconds: 300),
reverseDuration: const Duration(milliseconds: 500),
);
useEffect(() {
void onStateChange(AnimationStatus state) {
if (state == AnimationStatus.completed) {
controller.reverse();
} else if (state == AnimationStatus.dismissed) {
controller.forward();
}
}
controller.addStatusListener(onStateChange);
controller.forward();
return () {
controller.removeStatusListener(onStateChange);
};
}, [controller]);
final opacityTween = Tween(
begin: 0.7,
end: 1.0,
);
return FadeTransition(
opacity: opacityTween.animate(controller),
child: child,
);
}
}
class _UpAndDown extends HookWidget {
const _UpAndDown({
super.key,
required this.child,
});
final Widget child;
@override
Widget build(BuildContext context) {
final controller = useAnimationController(
duration: const Duration(milliseconds: 300),
reverseDuration: const Duration(milliseconds: 500),
);
useEffect(() {
void onStateChange(AnimationStatus state) {
if (state == AnimationStatus.completed) {
controller.reverse();
} else if (state == AnimationStatus.dismissed) {
controller.forward();
}
}
controller.addStatusListener(onStateChange);
controller.forward();
return () {
controller.removeStatusListener(onStateChange);
};
}, [controller]);
final offsetTween = Tween(
begin: const Offset(0, 0.2),
end: const Offset(0, 0),
);
return SlideTransition(
position: offsetTween.animate(controller),
child: child,
);
}
}

View File

@ -182,7 +182,7 @@ class SwipeNextPageHandler extends StatelessWidget {
} }
}, },
onPanCancel: () { onPanCancel: () {
controller.animateTo(controller.lowerBound, curve: Curves.easeIn);
}, },
onPanUpdate: (details) { onPanUpdate: (details) {
controller.value -= details.delta.dy; controller.value -= details.delta.dy;