dreampad/lib/app/modules/welcome/views/partner_widget.dart

354 lines
14 KiB
Dart
Raw Normal View History

2023-11-29 20:37:45 +08:00
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:dreampad/app/routes/app_pages.dart';
import 'package:dreampad/app/shared/constants/constants.dart';
import 'package:dreampad/app/shared/shared.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import '../controllers/welcome_controller.dart';
class PartnerWidget extends HookWidget {
const PartnerWidget({super.key});
WelcomeController get controller => Get.find<WelcomeController>();
@override
Widget build(BuildContext context) {
final isPartnerDone = useState(false);
return !isPartnerDone.value
? buildPartner(context, isPartnerDone)
: buildConfirm(context);
}
Widget buildPartner(BuildContext context, ValueNotifier<bool> isPartnerDone) {
return LayoutBuilder(builder: (context, constraint) {
return HookBuilder(builder: (context) {
final isIpShown = useState(false);
final isDialogShown = useState(false);
final isTextShown = useState(false);
final animationController = useAnimationController(
duration: const Duration(milliseconds: 500),
lowerBound: 0,
upperBound: constraint.maxHeight);
final fadeoutAnimation = (1 -
useListenableSelector(
animationController,
() =>
animationController.value /
animationController.upperBound,
))
.toDouble();
useEffect(() {
void onAnimationStateChange(AnimationStatus state) {
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
if (state == AnimationStatus.completed) {
isPartnerDone.value = true;
}
});
}
animationController.addStatusListener(onAnimationStateChange);
return () {
animationController.removeStatusListener(onAnimationStateChange);
};
}, [animationController]);
return SwipePageHandlerReceiver(
controller: animationController,
currentIndex: useState(0),
child: AnimatedBuilder(
animation: animationController,
builder: (context, _) => Stack(
children: [
const _Background(),
Positioned(
bottom: 5.h + animationController.value,
left: 452.w,
child: Center(
child: AnimatedVisibilityWidget(
duration: const Duration(milliseconds: 500),
isVisible: isTextShown.value,
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
child: IgnorePointer(
ignoring: !isTextShown.value,
child: SwipeNextPageHandler(
child: Column(
children: [
Images.up,
Images.welcomeBegin,
],
),
),
),
),
)),
Stack(
children: [
Positioned(
top: 42.h,
left: 149.w,
child: AnimatedVisibilityWidget(
isVisible: true,
duration: const Duration(milliseconds: 500),
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isInitAnimated: true,
onDone: (visible) {
if (visible) {
isIpShown.value = true;
}
},
child: Images.ip,
),
),
Positioned(
top: 76.h,
left: 451.w,
child: Opacity(
opacity: fadeoutAnimation,
child: AnimatedVisibilityWidget(
isVisible: isIpShown.value,
duration: const Duration(milliseconds: 500),
animationWidgetBuilder: AnimatedVisibilityWidget
.fadeAnimationWidgetBuilder,
onDone: (visible) {
if (visible) {
isDialogShown.value = true;
}
},
child: Container(
width: 465.w,
height: 221.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.welcomeDialog,
fit: BoxFit.fill,
),
),
padding: REdgeInsets.only(
top: 45.0, left: 45.0, right: 45.0),
child: DefaultTextStyle(
style: TextStyles.mediumWhiteShadowHeight18_034,
child: Visibility(
visible: isDialogShown.value,
child: AnimatedTextKit(
totalRepeatCount: 1,
animatedTexts: [
TypewriterAnimatedText(
'${controller.textController.text}你好! 我是一只天马。我们天马族一直生活在这里。与探梦者为伴。接下来让我来做你探索的伙伴吧。',
speed: const Duration(milliseconds: 150),
cursor: '',
),
],
onFinished: () {
isTextShown.value = true;
},
),
),
),
),
),
),
),
],
),
],
),
),
);
});
});
}
Widget buildConfirm(BuildContext context) {
return HookBuilder(builder: (context) {
final isDialogShown = useState(false);
final isTextShown = useState(false);
2023-11-30 10:16:09 +08:00
final fadeOutAnimationController = useAnimationController(
initialValue: 1.0,
duration: const Duration(milliseconds: 500),
);
2023-11-29 20:37:45 +08:00
return Stack(
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectBg,
fit: BoxFit.fill,
),
),
),
),
2023-11-30 10:16:09 +08:00
Positioned(
top: 42.h,
left: 149.w,
child: FadeTransition(
opacity: fadeOutAnimationController,
child: Images.ip,
),
),
2023-11-29 20:37:45 +08:00
Positioned(
top: 76.h,
left: 451.w,
2023-11-30 10:16:09 +08:00
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,
),
2023-11-29 20:37:45 +08:00
),
2023-11-30 10:16:09 +08:00
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;
},
),
2023-11-29 20:37:45 +08:00
),
),
),
2023-11-30 10:16:09 +08:00
const RSizedBox(
height: 36.0,
2023-11-29 20:37:45 +08:00
),
2023-11-30 10:16:09 +08:00
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,
),
],
),
2023-11-29 20:37:45 +08:00
),
),
),
),
],
);
});
}
}
class _Background extends StatelessWidget {
const _Background();
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraint) => HookBuilder(builder: (context) {
final controller = SwipeNextPageContainer.of(context)!.controller;
return AnimatedBuilder(
animation: controller,
builder: (context, _) => HookBuilder(builder: (context) {
final hasFinished = useState(false);
final animationValue = hasFinished.value
? controller.upperBound
: controller.value;
useEffect(() {
void onAnimationStateChange(AnimationStatus state) {
if (state == AnimationStatus.completed) {
SchedulerBinding.instance
.addPostFrameCallback((timeStamp) {
hasFinished.value = true;
});
}
}
controller.addStatusListener(onAnimationStateChange);
return () {
controller
.removeStatusListener(onAnimationStateChange);
};
}, [controller]);
return Stack(
children: [
Positioned(
top: 0 - animationValue,
left: 0,
right: 0,
child: Container(
width: constraint.maxWidth,
height: constraint.maxHeight,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.welcomeBg,
fit: BoxFit.fill,
),
),
),
),
Positioned(
top: controller.upperBound - animationValue - 1,
left: 0,
right: 0,
child: Container(
width: constraint.maxWidth,
height: constraint.maxHeight,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectBg,
fit: BoxFit.fill,
),
),
),
),
],
);
}));
}));
}
}