diff --git a/lib/app/modules/home/widgets/first_time_dialog.dart b/lib/app/modules/home/widgets/first_time_dialog.dart index 9824058..d044296 100644 --- a/lib/app/modules/home/widgets/first_time_dialog.dart +++ b/lib/app/modules/home/widgets/first_time_dialog.dart @@ -66,6 +66,7 @@ class FirstTimeDialog extends StatelessWidget { left: 0, right: 0, child: AnimatedVisibilityWidget( + animationWidgetBuilder: AnimatedVisibilityWidget.fadeAnimationWidgetBuilder, isVisible: isTextShown.value, child: const Center( child: TouchHintWidget(), diff --git a/lib/app/modules/select/controllers/select_controller.dart b/lib/app/modules/select/controllers/select_controller.dart index 3e940ce..61b3883 100644 --- a/lib/app/modules/select/controllers/select_controller.dart +++ b/lib/app/modules/select/controllers/select_controller.dart @@ -68,6 +68,15 @@ class SelectController extends GetxController { occupations.add(Occupation( id: 4, gender: 2, + name: '运动员', + enName: 'athletes', + vImage: 'btn_male_pic_athletes', + hImage: 'pic_male_athletes', + selected: false, + )); + occupations.add(Occupation( + id: 5, + gender: 2, name: '画家', enName: 'artist', vImage: 'btn_male_pic_artist', @@ -75,16 +84,6 @@ class SelectController extends GetxController { selected: 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( id: 6, gender: 2, diff --git a/lib/app/modules/welcome/views/partner_widget.dart b/lib/app/modules/welcome/views/partner_widget.dart index 8e924de..94c5280 100644 --- a/lib/app/modules/welcome/views/partner_widget.dart +++ b/lib/app/modules/welcome/views/partner_widget.dart @@ -168,6 +168,10 @@ class PartnerWidget extends HookWidget { return HookBuilder(builder: (context) { final isDialogShown = useState(false); final isTextShown = useState(false); + final fadeOutAnimationController = useAnimationController( + initialValue: 1.0, + duration: const Duration(milliseconds: 500), + ); return Stack( children: [ Positioned.fill( @@ -180,82 +184,94 @@ 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( top: 76.h, left: 451.w, - child: AnimatedVisibilityWidget( - isVisible: true, - duration: const Duration(milliseconds: 500), - animationWidgetBuilder: - AnimatedVisibilityWidget.fadeAnimationWidgetBuilder, - isInitAnimated: true, - onDone: (visible) { - if (visible) { - isDialogShown.value = true; - } - }, - child: Container( - width: 464.w, - height: 270.h, - decoration: const BoxDecoration( - image: DecorationImage( - image: Images.questionDialog, - fit: BoxFit.fill, + child: FadeTransition( + opacity: fadeOutAnimationController, + child: AnimatedVisibilityWidget( + isVisible: true, + duration: const Duration(milliseconds: 500), + animationWidgetBuilder: + AnimatedVisibilityWidget.fadeAnimationWidgetBuilder, + isInitAnimated: true, + onDone: (visible) { + if (visible) { + isDialogShown.value = true; + } + }, + child: Container( + width: 464.w, + height: 270.h, + decoration: const BoxDecoration( + image: DecorationImage( + image: Images.questionDialog, + fit: BoxFit.fill, + ), ), - ), - padding: REdgeInsets.only(top: 45.0, left: 45.0, right: 45.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: SizedBox( - width: double.infinity, - child: Visibility( - visible: isDialogShown.value, - child: AnimatedTextKit( - totalRepeatCount: 1, - animatedTexts: [ - TypewriterAnimatedText( - '每个来到建木之境的探梦者,都需要先选定自己的【梦想职业】,才能继续探索哦。准备好了吗?', - textStyle: TextStyles.mediumWhiteShadow18_034, - textAlign: TextAlign.start, - speed: const Duration(milliseconds: 150), - cursor: '', - ), - ], - onFinished: () { - isTextShown.value = true; - }, + padding: REdgeInsets.only(top: 45.0, left: 45.0, right: 45.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + width: double.infinity, + child: Visibility( + visible: isDialogShown.value, + child: AnimatedTextKit( + totalRepeatCount: 1, + pause: Duration.zero, + animatedTexts: [ + TypewriterAnimatedText( + '每个来到建木之境的探梦者,都需要先选定自己的【梦想职业】,才能继续探索哦。准备好了吗?', + textStyle: TextStyles.mediumWhiteShadow18_034, + textAlign: TextAlign.start, + speed: const Duration(milliseconds: 150), + cursor: '', + ), + ], + onFinished: () { + isTextShown.value = true; + }, + ), ), ), ), - ), - const RSizedBox( - height: 36.0, - ), - AnimatedVisibilityWidget( - isVisible: isTextShown.value, - duration: const Duration(milliseconds: 500), - animationWidgetBuilder: - AnimatedVisibilityWidget.fadeAnimationWidgetBuilder, - child: ImageTxtButton( - text: '准备好了', - imgName: 'question/btn_icon_begin', - textStyle: TextStyles.mediumWhite20_014, - width: 186.0, - height: 54.0, - onPressed: () async { - await controller.confirm(); - await Get.offAllNamed(Routes.SELECT); - }, + const RSizedBox( + height: 36.0, ), - ), - const RSizedBox( - height: 64.0, - ), - ], + AnimatedVisibilityWidget( + isVisible: isTextShown.value, + duration: const Duration(milliseconds: 500), + animationWidgetBuilder: + AnimatedVisibilityWidget.fadeAnimationWidgetBuilder, + child: ImageTxtButton( + text: '准备好了', + imgName: 'question/btn_icon_begin', + textStyle: TextStyles.mediumWhite20_014, + width: 186.0, + height: 54.0, + onPressed: () async { + await controller.confirm(); + await fadeOutAnimationController.reverse(); + await Get.offAllNamed(Routes.SELECT); + }, + ), + ), + const RSizedBox( + height: 64.0, + ), + ], + ), ), ), ), diff --git a/lib/app/modules/welcome/views/welcome_view.dart b/lib/app/modules/welcome/views/welcome_view.dart index b29660a..5f24c01 100644 --- a/lib/app/modules/welcome/views/welcome_view.dart +++ b/lib/app/modules/welcome/views/welcome_view.dart @@ -41,6 +41,7 @@ class WelcomeView extends GetView { : AnimatedVisibilityWidget( isVisible: !finishInput.value, duration: const Duration(milliseconds: 800), + curve: Curves.fastOutSlowIn, animationWidgetBuilder: AnimatedVisibilityWidget .fadeAnimationWidgetBuilder, onDone: (visible) { diff --git a/lib/app/shared/constants/images.dart b/lib/app/shared/constants/images.dart index 50f1595..99ef6fa 100644 --- a/lib/app/shared/constants/images.dart +++ b/lib/app/shared/constants/images.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../utils/image_utils.dart'; @@ -17,10 +18,13 @@ class Images { width: 35.w, ); - static Widget up = LoadAssetImage( - 'btn_icon_up', - height: 47.w, - width: 47.w, + static Widget up = _UpAndDown( + child: LoadAssetImage( + 'btn_icon_up', + fit: BoxFit.contain, + height: 47.w, + width: 47.w, + ), ); static Widget ip = LoadAssetImage( @@ -43,16 +47,20 @@ class Images { fit: BoxFit.fill, ); - static Widget splashBegin = LoadAssetImage( - 'splash/btn_icon_begin', - height: 105.h, - width: 378.w, + static Widget splashBegin = _FadeInAndOut( + child: LoadAssetImage( + 'splash/btn_icon_begin', + height: 105.h, + width: 378.w, + ), ); - static Widget welcomeBegin = LoadAssetImage( - 'welcome/btn_label_bg_up', - height: 114.h, - width: 270.w, + static Widget welcomeBegin = _FadeInAndOut( + child: LoadAssetImage( + 'welcome/btn_label_bg_up', + height: 114.h, + width: 270.w, + ), ); static Widget pullDown = LoadAssetImage( @@ -61,10 +69,12 @@ class Images { width: 21.w, ); - static Widget pullUp = LoadAssetImage( - 'welcome/btn_icon_up', - height: 21.w, - width: 21.w, + static Widget pullUp = _UpAndDown( + child: LoadAssetImage( + 'welcome/btn_icon_up', + height: 21.w, + width: 21.w, + ), ); static Widget selectPre = LoadAssetImage( @@ -79,16 +89,20 @@ class Images { width: 24.w, ); - static Widget questionRecommended = LoadAssetImage( - 'question/label_recommended', - height: 105.h, - width: 390.w, + static Widget questionRecommended = _FadeInAndOut( + child: LoadAssetImage( + 'question/label_recommended', + height: 105.h, + width: 390.w, + ), ); - static Widget homeCreate = LoadAssetImage( - 'home/label_label_create', - height: 105.h, - width: 378.w, + static Widget homeCreate = _FadeInAndOut( + child: LoadAssetImage( + 'home/label_label_create', + height: 105.h, + width: 378.w, + ), ); static Widget homeReset = LoadAssetImage( @@ -319,3 +333,83 @@ class Images { static const AssetImage avatarUser = 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, + ); + } +} diff --git a/lib/app/shared/widgets/swipe_next_page_container.dart b/lib/app/shared/widgets/swipe_next_page_container.dart index fe08991..0365eda 100644 --- a/lib/app/shared/widgets/swipe_next_page_container.dart +++ b/lib/app/shared/widgets/swipe_next_page_container.dart @@ -182,7 +182,7 @@ class SwipeNextPageHandler extends StatelessWidget { } }, onPanCancel: () { - controller.animateTo(controller.lowerBound, curve: Curves.easeIn); + }, onPanUpdate: (details) { controller.value -= details.delta.dy;