优化动画效果

This commit is contained in:
yuanjunyao 2023-11-30 14:58:48 +08:00
parent d950901497
commit e32cd247dd
14 changed files with 749 additions and 541 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -34,7 +34,10 @@ class HomeController extends GetxController {
final knowledgePoints = RxList<Rx<KnowledgePoint>>([]);
final knowledgePointDialogues = RxList<KnowledgePointDialogue?>([]);
final chatInputMsg = ''.obs;
final remainTimeStr = '45:00'.obs;
late final remainTimeStr =
'${(kTotalTimer ~/ 60).toString().padLeft(2, '0')}:${(kTotalTimer % 60).toString().padLeft(2, '0')}'
.obs;
final remainTime = kTotalTimer.obs;
final availableApp = false.obs;
late String account = '琉璃';
@ -53,8 +56,12 @@ class HomeController extends GetxController {
final scrollController = ScrollController();
late TextEditingController textController = TextEditingController();
Timer? exploreTimer;
late int countTime = 45 * 60;
static const kTotalTimer = 2 * 60;
late int countTime = kTotalTimer;
// late int countTime = 45 * 60;
final repeatPeriod = const Duration(seconds: 1);
@override
void onInit() {
super.onInit();
@ -111,7 +118,8 @@ class HomeController extends GetxController {
explored.value = false;
exploreCount.value = 0;
availableApp.value = false;
countTime = 45 * 60;
countTime = kTotalTimer;
remainTime.value = kTotalTimer;
exploreTimer!.cancel();
exploreTimer = null;
return;
@ -131,6 +139,7 @@ class HomeController extends GetxController {
str = '$str$second';
}
remainTimeStr.value = str;
remainTime.value = countTime;
});
} else {
exploreTimer!.cancel();
@ -407,28 +416,28 @@ class HomeController extends GetxController {
void initArtistGoals() {
goals.add(
Goal(id: 1, occupationId: 1, age: age + 0, title: '今年目标', contents: [
Goal(id: 1, occupationId: 5, age: age + 0, title: '今年目标', contents: [
GoalContent(title: '基础绘画技巧', content: '学习和练习基础的绘画技巧,如素描、色彩等。'),
GoalContent(title: '艺术欣赏能力', content: '参观美术馆、画展,增进对不同画派和风格的了解。'),
GoalContent(title: '创意表达培养', content: '通过日常生活的观察和想象,创作一些个人作品。'),
]));
goals.add(
Goal(id: 2, occupationId: 1, age: age + 3, title: '三年目标', contents: [
Goal(id: 2, occupationId: 5, age: age + 3, title: '三年目标', contents: [
GoalContent(title: '基础绘画技巧', content: '尝试不同的绘画媒介和技巧,开始探索个人的艺术风格。'),
GoalContent(title: '艺术欣赏能力', content: '参加美术课程或夏令营,系统学习绘画知识。'),
GoalContent(title: '创意表达培养', content: '参加学校或社区的绘画比赛和展览,锻炼展示自己作品的能力。'),
]));
goals.add(Goal(id: 3, occupationId: 1, title: '18岁目标', contents: [
goals.add(Goal(id: 3, occupationId: 5, title: '18岁目标', contents: [
GoalContent(title: '艺术类院校申请', content: '申请艺术类高中或大学,接受正规的艺术教育。'),
GoalContent(title: '艺术实践加强', content: '通过参加画展、艺术竞赛等,增加实践经验。'),
GoalContent(title: '艺术理论学习', content: '学习艺术史、美学等,增强艺术理论素养。'),
]));
goals.add(Goal(id: 4, occupationId: 1, title: '22岁目标', contents: [
goals.add(Goal(id: 4, occupationId: 5, title: '22岁目标', contents: [
GoalContent(title: '专业深造', content: '在艺术类大学深入学习绘画,探索个人艺术方向。'),
GoalContent(title: '国际视野拓展', content: '参与国际艺术交流活动,了解全球艺术潮流。'),
GoalContent(title: '独立创作展示', content: '举办个人画展或参加重要艺术展览,展示个人作品。'),
]));
goals.add(Goal(id: 5, occupationId: 1, title: '30岁目标', contents: [
goals.add(Goal(id: 5, occupationId: 5, title: '30岁目标', contents: [
GoalContent(title: '个人品牌建立', content: '作为画家在艺术界建立良好的个人品牌和声誉。'),
GoalContent(title: '艺术教育贡献', content: '通过教学或工作坊等方式分享艺术知识和技巧。'),
GoalContent(title: '国际艺术影响力', content: '作品具有国际影响力,参与国际艺术交流与合作。'),
@ -437,28 +446,28 @@ class HomeController extends GetxController {
void initAcademicianGoals() {
goals.add(
Goal(id: 1, occupationId: 2, age: age + 0, title: '今年目标', contents: [
Goal(id: 1, occupationId: 1, age: age + 0, title: '今年目标', contents: [
GoalContent(title: '课外阅读提升', content: '选择与科学相关的儿童图书,每周至少阅读一本。'),
GoalContent(title: '科学兴趣培养', content: '参加科学实验兴趣小组或课外科学俱乐部,增进对科学的兴趣和理解。'),
GoalContent(title: '基础数学能力', content: '每天坚持数学练习,提高逻辑思维和解决问题的能力。'),
]));
goals.add(
Goal(id: 2, occupationId: 2, age: age + 3, title: '三年目标', contents: [
Goal(id: 2, occupationId: 1, age: age + 3, title: '三年目标', contents: [
GoalContent(title: '科学竞赛参与', content: '参加学校或地区的科学竞赛,提高科学实践能力。'),
GoalContent(title: '英语能力加强', content: '科学领域英语是必备技能,提高英语水平以便阅读国际科学文献。'),
GoalContent(title: '拓展科学知识', content: '通过在线课程或夏令营等方式,学习物理、化学等更多科学知识。'),
]));
goals.add(Goal(id: 3, occupationId: 2, title: '18岁目标', contents: [
goals.add(Goal(id: 3, occupationId: 1, title: '18岁目标', contents: [
GoalContent(title: '理想大学申请', content: '申请国内外知名大学的科学相关专业,为深造打下基础。'),
GoalContent(title: '科学研究实习', content: '在大学期间尽早寻找实习机会,加入科研团队。'),
GoalContent(title: '专业网络构建', content: '建立与科学家和研究人员的联系,拓宽学术交流圈。'),
]));
goals.add(Goal(id: 4, occupationId: 2, title: '22岁目标', contents: [
goals.add(Goal(id: 4, occupationId: 1, title: '22岁目标', contents: [
GoalContent(title: '硕士/博士深造', content: '申请硕士或直接博士项目,深入专业领域研究。'),
GoalContent(title: '学术论文发表', content: '在专业期刊上发表研究成果,建立学术声誉。'),
GoalContent(title: '国际科研合作', content: '参与国际科研项目,扩大研究视野。'),
]));
goals.add(Goal(id: 5, occupationId: 2, title: '30岁目标', contents: [
goals.add(Goal(id: 5, occupationId: 1, title: '30岁目标', contents: [
GoalContent(title: '科学研究突破', content: '在某一科学领域取得显著研究成果。'),
GoalContent(title: '科学社群领导', content: '在科学界承担一定的领导角色,如项目负责人或研究小组领头。'),
GoalContent(title: '学术影响力拓展', content: '通过公开讲座、论文发表等方式,提高在科学界的影响力。'),
@ -553,9 +562,16 @@ class HomeController extends GetxController {
);
chatMsgList.add(chatMsg);
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
Future.delayed(const Duration(milliseconds: 1000));
SchedulerBinding.instance.addPostFrameCallback((timeStamp) async {
scrollController.animateTo(
scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
});
await Future.delayed(const Duration(seconds: 1));
var knowledgePointDialogue = knowledgePointDialogues.firstWhere((t) =>
t!.kpId == selectKnowledge.value!.id && t.id == sendCount && t.isGpt!);
chatMsg = ChatMsg(
@ -567,8 +583,11 @@ class HomeController extends GetxController {
chatMsgList.add(chatMsg);
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
Future.delayed(const Duration(milliseconds: 300));
scrollController.jumpTo(scrollController.position.maxScrollExtent);
scrollController.animateTo(
scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
});
var knowledge = knowledgePoints

View File

@ -1,7 +1,6 @@
import 'package:dreampad/app/modules/home/models/chat_msg_model.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';
@ -110,7 +109,6 @@ class ExploreStudyView extends GetView<HomeController> {
controller.chatInputMsg.value.substring(0, i);
await Future.delayed(const Duration(milliseconds: 80));
}
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {});
});
return ChatInputWidget(
controller: controller.textController,

View File

@ -2,6 +2,7 @@ import 'package:dreampad/app/models/models.dart';
import 'package:dreampad/app/routes/app_pages.dart';
import 'package:dreampad/app/shared/constants/dimens.dart';
import 'package:dreampad/app/shared/shared.dart';
import 'package:dreampad/app/shared/widgets/touch_hint_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -31,11 +32,17 @@ class HomeView extends GetView<HomeController> {
child: Obx(
() => Scaffold(
backgroundColor: Colors.transparent,
body: controller.create.value
? Center(
child: Images.homeCreate,
)
: buildBody(context),
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: KeyedSubtree(
key: ValueKey(controller.create.value),
child: controller.create.value
? Center(
child: Images.homeCreate,
)
: buildBody(context),
),
),
),
),
),
@ -43,119 +50,137 @@ class HomeView extends GetView<HomeController> {
}
Widget buildBody(BuildContext context) {
return Obx(
() => Stack(
children: [
Container(
height: 458.h,
width: 996.w,
margin: REdgeInsets.only(
left: 90.0,
top: 178.0,
),
color: Colors.transparent,
child: controller.prompt.value ? null : buildApp(context),
),
Container(
height: 650.h,
width: 630.w,
margin: REdgeInsets.only(
left: 262.0,
top: 0.0,
),
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeTree,
fit: BoxFit.fill,
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: controller.explored2.value >= 4
? null
: () {
controller.explored2.value = controller.explored2.value + 1;
},
child: Obx(
() => Stack(
children: [
Container(
height: 458.h,
width: 996.w,
margin: REdgeInsets.only(
left: 90.0,
top: 178.0,
),
color: Colors.transparent,
child: controller.prompt.value ? null : buildApp(context),
),
child: treeWidget(),
),
Container(
height: 228.h,
width: 1176.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeColud,
fit: BoxFit.fill,
Container(
height: 650.h,
width: 630.w,
margin: REdgeInsets.only(
left: 262.0,
top: 0.0,
),
),
child: titleWidget(),
),
Container(
height: 650.h,
width: 630.w,
margin: REdgeInsets.only(
left: 262.0,
top: 0.0,
),
child: goalWidget(),
),
controller.prompt.value
? Container()
: Positioned(
left: 49.w,
top: 50.h,
child: UserWidget(
account: controller.account,
gender: controller.gender,
occupationName: controller.occupationName,
),
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeTree,
fit: BoxFit.fill,
),
controller.prompt.value
? Container()
: Positioned(
right: 49.w,
top: 50.h,
child: ExploreWidget(
explored: controller.explored.value,
exploreCount: controller.exploreCount.value,
remainTime: controller.remainTimeStr.value,
onPressed: () async {
controller.explorePress();
},
),
),
child: treeWidget(),
),
Container(
height: 228.h,
width: 1176.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeColud,
fit: BoxFit.fill,
),
controller.prompt.value
? Container()
: Positioned(
right: 0.w,
bottom: 0.h,
child: Container(
height: 24.h,
width: 69.w,
decoration: BoxDecoration(
color: const Color(0xFF000000).withOpacity(0.4),
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10.0).r),
),
child: titleWidget(),
),
Container(
height: 650.h,
width: 630.w,
margin: REdgeInsets.only(
left: 262.0,
top: 0.0,
),
child: goalWidget(),
),
controller.prompt.value
? Container()
: Positioned(
left: 49.w,
top: 50.h,
child: UserWidget(
account: controller.account,
gender: controller.gender,
occupationName: controller.occupationName,
),
padding: REdgeInsets.all(5.0),
child: GestureDetector(
onTap: () async {
await controller.reset();
),
controller.prompt.value
? Container()
: Positioned(
right: 49.w,
top: 50.h,
child: ExploreWidget(
explored: controller.explored.value,
exploreCount: controller.exploreCount.value,
remainTimePercent: controller.remainTime.value /
HomeController.kTotalTimer,
remainTimeStr: controller.remainTimeStr.value,
onPressed: () async {
controller.explorePress();
},
child: Text.rich(
TextSpan(
children: [
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Images.homeReset,
),
const WidgetSpan(child: RSizedBox(width: 2.0)),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Text(
'重新体验',
style: TextStyles.mediumWhite10,
),
),
Positioned(
left: 232.h,
bottom: 84.h,
child: AnimatedVisibilityWidget(
isVisible: controller.explored2.value < 4,
child: const TouchHintWidget(),
),
),
controller.prompt.value
? Container()
: Positioned(
right: 0.w,
bottom: 4.h,
child: Container(
height: 24.h,
width: 69.w,
decoration: BoxDecoration(
color: const Color(0xFF000000).withOpacity(0.4),
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(10.0).r),
),
padding: REdgeInsets.all(5.0),
child: GestureDetector(
onTap: () async {
await controller.reset();
},
child: Text.rich(
TextSpan(
children: [
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Images.homeReset,
),
),
],
const WidgetSpan(child: RSizedBox(width: 2.0)),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Text(
'重新体验',
style: TextStyles.mediumWhite10,
),
),
],
),
),
),
),
),
),
],
],
),
),
);
}
@ -204,144 +229,163 @@ class HomeView extends GetView<HomeController> {
}
Widget fourthGoalWidget() {
return Stack(
children: [
Positioned(
left: 115.w,
top: 102.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {},
child: Text(
'更长期目标',
style: TextStyles.boldWhiteShadow18_111,
return _TextShowUp(
child: Stack(
children: [
Positioned(
left: 115.w,
top: 102.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {},
child: Text(
'更长期目标',
style: TextStyles.boldWhiteShadow18_111,
),
),
),
),
Positioned(
left: 28.w,
top: 62.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
showGoalDialog(controller.getGoal(3));
},
child: Text(
'18岁目标',
style: TextStyles.boldWhiteShadow14_111,
Positioned(
left: 20.w,
top: 56.h,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
showGoalDialog(controller.getGoal(3));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'18岁目标',
style: TextStyles.boldWhiteShadow14_111,
),
),
),
),
),
Positioned(
left: 52.w,
top: 129.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
showGoalDialog(controller.getGoal(4));
},
child: Text(
'22岁目标',
style: TextStyles.boldWhiteShadow14_111,
Positioned(
left: 44.w,
top: 121.h,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
showGoalDialog(controller.getGoal(4));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'22岁目标',
style: TextStyles.boldWhiteShadow14_111,
),
),
),
),
),
Positioned(
left: 128.w,
top: 168.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
showGoalDialog(controller.getGoal(4));
},
child: Text(
'30岁目标',
style: TextStyles.boldWhiteShadow14_111,
Positioned(
left: 120.w,
top: 160.h,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
showGoalDialog(controller.getGoal(5));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'30岁目标',
style: TextStyles.boldWhiteShadow14_111,
),
),
),
),
),
],
],
),
);
}
Widget thirdGoalWidget() {
return Stack(
children: [
Positioned(
left: 51.w,
top: 102.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
showGoalDialog(controller.getGoal(2));
},
child: Text(
'三年内目标',
style: TextStyles.boldWhiteShadow18_111,
return _TextShowUp(
child: Stack(
children: [
Positioned(
left: 42.w,
top: 94.h,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
showGoalDialog(controller.getGoal(2));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'三年内目标',
style: TextStyles.boldWhiteShadow18_111,
),
),
),
),
),
Positioned(
right: 56.w,
top: 61.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'科学竞赛参与',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
Positioned(
right: 56.w,
top: 61.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'科学竞赛参与',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
),
Positioned(
right: 66.w,
top: 123.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'英语能力加强',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
Positioned(
right: 66.w,
top: 123.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'英语能力加强',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
),
Positioned(
left: 98.w,
bottom: 18.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'拓展科学知识',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
Positioned(
left: 98.w,
bottom: 18.h,
child: Container(
height: 36.h,
width: 56.w,
color: Colors.transparent,
child: Text(
'拓展科学知识',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
),
],
],
),
);
}
Widget secondGoalWidget() {
return _ShowUp(
return _TextShowUp(
child: Stack(
children: [
Positioned(
left: 43.w,
top: 66.h,
left: 35.w,
top: 58.h,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
behavior: HitTestBehavior.translucent,
onTap: () {
showGoalDialog(controller.getGoal(1));
},
child: Text(
'今年目标',
style: TextStyles.boldWhiteShadow18_111,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'今年目标',
style: TextStyles.boldWhiteShadow18_111,
),
),
),
),
@ -355,7 +399,7 @@ class HomeView extends GetView<HomeController> {
child: Text(
'课外阅读提升',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
@ -369,7 +413,7 @@ class HomeView extends GetView<HomeController> {
child: Text(
'科学兴趣培养',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
@ -383,7 +427,7 @@ class HomeView extends GetView<HomeController> {
child: Text(
'基础教学能力',
textAlign: TextAlign.center,
style: TextStyles.boldWhiteShadow14_111,
style: TextStyles.boldWhiteShadow12_111,
),
),
),
@ -411,180 +455,178 @@ class HomeView extends GetView<HomeController> {
}
Widget treeWidget() {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: controller.explored2.value >= 4
? null
: () {
controller.explored2.value = controller.explored2.value + 1;
},
child: Stack(
children: [
Positioned(
left: 218.w,
top: 244.h,
child: GestureDetector(
onTap: controller.explored2.value >= 4
? () async {
await Get.toNamed(Routes.HOME + Routes.EXPLORE);
}
: null,
child: Container(
width: 210.w,
height: 216.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeShine,
fit: BoxFit.fill,
),
return Stack(
children: [
Positioned(
left: 218.w,
top: 244.h,
child: GestureDetector(
onTap: controller.explored2.value >= 4
? () async {
await Get.toNamed(Routes.HOME + Routes.EXPLORE);
}
: null,
child: Container(
width: 210.w,
height: 216.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeShine,
fit: BoxFit.fill,
),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'梦想',
style: TextStyles.boldWhiteShadow22_012,
),
Text(
'探索',
style: TextStyles.boldWhiteShadow22_012,
)
],
),
),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'梦想',
style: TextStyles.boldWhiteShadow22_012,
),
Text(
'探索',
style: TextStyles.boldWhiteShadow22_012,
)
],
),
),
),
),
controller.explored2.value >= 4
? Positioned(
left: 15.w,
top: 20.h,
child: _ShowUp(
child: Container(
height: 311.h,
width: 230.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeFourthLeaf,
fit: BoxFit.fill,
),
),
controller.explored2.value >= 4
? Positioned(
left: 15.w,
top: 20.h,
child: _LeafGrowUp(
alignment: const Alignment(0.9, 0.1),
child: Container(
height: 311.h,
width: 230.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeFourthLeaf,
fit: BoxFit.fill,
),
),
),
)
: Container(),
controller.explored2.value >= 3
? Positioned(
left: 352.w,
top: 0.0,
child: _ShowUp(
child: Container(
height: 221.h,
width: 281.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeThirdLeaf,
fit: BoxFit.fill,
),
),
)
: Container(),
controller.explored2.value >= 3
? Positioned(
left: 352.w,
top: 0.0,
child: _LeafGrowUp(
alignment: const Alignment(
-0.9,
0.3,
),
child: Container(
height: 221.h,
width: 281.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeThirdLeaf,
fit: BoxFit.fill,
),
),
),
)
: Container(),
controller.explored2.value >= 2
? Positioned(
left: 363.w,
top: 180.h,
child: _ShowUp(
child: Container(
height: 240.h,
width: 240.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeSecondLeaf,
fit: BoxFit.fill,
),
),
)
: Container(),
controller.explored2.value >= 2
? Positioned(
left: 363.w,
top: 180.h,
child: _LeafGrowUp(
alignment: const Alignment(-1, -0.5),
child: Container(
height: 240.h,
width: 240.w,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.homeSecondLeaf,
fit: BoxFit.fill,
),
),
),
)
: Container(),
controller.explored2.value >= 1 ? firstLeafWidget() : Container(),
LanternWidget(
brightCount: controller.exploreCount.value >= 2
? controller.exploreDay.value
: controller.exploreDay.value - 1,
),
Positioned(
left: 168.w,
top: 244.h,
child: Images.homeIp,
),
Positioned(
left: 135.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'智慧编程',
Images.homeMainAppProgramme,
Images.homeProgramme,
Images.homeProgrammeGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFFFFBC5A),
fontWeight: FontWeight.bold,
),
controller.explored.value,
)
: Container(),
controller.explored2.value >= 1 ? firstLeafWidget() : Container(),
LanternWidget(
brightCount: controller.exploreCount.value >= 2
? controller.exploreDay.value
: controller.exploreDay.value - 1,
),
Positioned(
left: 168.w,
top: 244.h,
child: Images.homeIp,
),
Positioned(
left: 135.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'智慧编程',
Images.homeMainAppProgramme,
Images.homeProgramme,
Images.homeProgrammeGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFFFFBC5A),
fontWeight: FontWeight.bold,
),
controller.explored.value,
),
),
Positioned(
left: 316.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'绘本创作',
Images.homeMainAppPictureBook,
Images.homePicturebook,
Images.homePicturebookGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFF68FFFA),
fontWeight: FontWeight.bold,
),
controller.explored.value,
),
Positioned(
left: 316.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'绘本创作',
Images.homeMainAppPictureBook,
Images.homePicturebook,
Images.homePicturebookGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFF68FFFA),
fontWeight: FontWeight.bold,
),
controller.explored.value,
),
),
Positioned(
right: 79.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'乐曲创作',
Images.homeMainAppMusic,
Images.homeMusic,
Images.homeMusicGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFFEA74DF),
fontWeight: FontWeight.bold,
),
controller.explored.value,
),
Positioned(
right: 79.w,
bottom: 10.h,
child: GestureDetector(
onTap: () {},
child: buildMainApp(
'乐曲创作',
Images.homeMainAppMusic,
Images.homeMusic,
Images.homeMusicGrey,
TextStyle(
fontSize: Dimens.font_sp10.sp,
fontFamily: 'alph-b',
color: const Color(0xFFEA74DF),
fontWeight: FontWeight.bold,
),
controller.explored.value,
),
),
],
),
),
],
);
}
@ -635,7 +677,8 @@ class HomeView extends GetView<HomeController> {
return Positioned(
right: 68.w,
top: 326.h,
child: _ShowUp(
child: _LeafGrowUp(
alignment: const Alignment(-1, 0),
child: Container(
height: 60.h,
width: 171.w,
@ -650,9 +693,11 @@ class HomeView extends GetView<HomeController> {
Positioned(
left: 23.w,
top: 26.h,
child: Text(
'本月已点亮${controller.exploreCount.value}个知识点',
style: TextStyles.mediumWhiteShadow12_111,
child: _TextShowUp(
child: Text(
'本月已点亮${controller.exploreCount.value}个知识点',
style: TextStyles.mediumWhiteShadow12_111,
),
),
),
],
@ -718,9 +763,43 @@ class HomeView extends GetView<HomeController> {
}
}
class _ShowUp extends HookWidget {
const _ShowUp({
super.key,
class _LeafGrowUp extends HookWidget {
const _LeafGrowUp({
required this.child,
required this.alignment,
});
final Widget child;
final Alignment alignment;
@override
Widget build(BuildContext context) {
final controller =
useAnimationController(duration: const Duration(milliseconds: 2000));
useMemoized(() {
controller.forward();
});
final shakeTween = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 0.0, end: 0.08), weight: 0.2),
TweenSequenceItem(tween: Tween(begin: 0.08, end: -0.03), weight: 0.2),
TweenSequenceItem(tween: Tween(begin: -0.03, end: 0.0), weight: 0.2),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 0.0), weight: 0.3),
]);
return RotationTransition(
turns: shakeTween.animate(controller),
alignment: alignment,
child: ScaleTransition(
scale: CurvedAnimation(curve: Curves.fastOutSlowIn, parent: controller),
alignment: alignment,
child: child,
),
);
}
}
class _TextShowUp extends HookWidget {
const _TextShowUp({
required this.child,
});
@ -730,7 +809,8 @@ class _ShowUp extends HookWidget {
Widget build(BuildContext context) {
final controller =
useAnimationController(duration: const Duration(milliseconds: 300));
useMemoized(() {
useMemoized(() async {
await Future.delayed(const Duration(milliseconds: 2000));
controller.forward();
});
return FadeTransition(

View File

@ -1,5 +1,6 @@
import 'package:dreampad/app/shared/shared.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ExploreWidget extends StatefulWidget {
@ -8,79 +9,161 @@ class ExploreWidget extends StatefulWidget {
required this.explored,
required this.exploreCount,
this.onPressed,
this.remainTime,
required this.remainTimePercent,
this.remainTimeStr,
});
final bool explored;
final int exploreCount;
final String? remainTime;
final double remainTimePercent;
final String? remainTimeStr;
final VoidCallback? onPressed;
@override
State<ExploreWidget> createState() => _ExploreWidgetState();
}
class _ExploreWidgetState extends State<ExploreWidget> {
late bool suspend = false;
@override
Widget build(BuildContext context) {
return Container(
height: 67.h,
width: 201.w,
decoration: BoxDecoration(
image: DecorationImage(
image: widget.explored
? Images.homeExplorePre
: Images.homeExploreDefault,
fit: BoxFit.fill,
),
),
child: Row(
children: [
const RSizedBox(width: 10.0),
GestureDetector(
onTap: () {
if (widget.explored) {
setState(() {
suspend = !suspend;
});
widget.onPressed?.call();
}
},
child: widget.explored
? suspend
? Images.homeExploreCountdown
: Images.homeExploreBegin
: Images.homeBeginGray,
return AnimatedSwitcher(
duration: kThemeAnimationDuration,
child: KeyedSubtree(
key: ValueKey(widget.explored),
child: Container(
height: 67.h,
width: 201.w,
decoration: BoxDecoration(
image: DecorationImage(
image: widget.explored
? Images.homeExplorePre
: Images.homeExploreDefault,
fit: BoxFit.fill,
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
child: Row(
children: [
Text(
'自由探索',
style: widget.explored
? TextStyles.boldWhiteShadow22_101
: TextStyles.boldWhiteShadow22_100,
const RSizedBox(width: 10.0),
GestureDetector(
onTap: () {
if (widget.explored) {
setState(() {
suspend = !suspend;
});
widget.onPressed?.call();
}
},
child: widget.explored
? _TimerCounter(
value: widget.remainTimePercent,
suspend: suspend,
)
: Images.homeBeginGray,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'自由探索',
style: widget.explored
? TextStyles.boldWhiteShadow22_101
: TextStyles.boldWhiteShadow22_100,
),
const RSizedBox(height: 4.0),
widget.explored
? Text(
'剩余时间:${widget.remainTimeStr}',
style: TextStyles.mediumWhiteShadow14_101,
)
: Row(
children: [
widget.exploreCount == 0
? Images.homeProgressBar
: Images.homeProgressBarIn,
const RSizedBox(width: 1.0),
widget.exploreCount >= 2
? Images.homeProgressBarIn
: Images.homeProgressBar,
],
),
],
),
const RSizedBox(height: 4.0),
widget.explored
? Text(
'剩余时间:${widget.remainTime}',
style: TextStyles.mediumWhiteShadow14_101,
)
: Row(
children: [
widget.exploreCount == 0
? Images.homeProgressBar
: Images.homeProgressBarIn,
const RSizedBox(width: 1.0),
widget.exploreCount >= 2
? Images.homeProgressBarIn
: Images.homeProgressBar,
],
),
],
),
],
),
),
);
}
}
class _TimerCounter extends StatelessWidget {
const _TimerCounter({
required this.value,
required this.suspend,
});
final double value;
final bool suspend;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 8),
child: SizedBox.square(
dimension: 45.h,
child: Stack(
children: [
Positioned.fill(
child: HookBuilder(
builder: (context) {
final animationController = useAnimationController(
duration: const Duration(seconds: 2),
);
useMemoized(() {
if (animationController.value < value) {
animationController.animateTo(value);
} else {
animationController.animateBack(value);
}
}, [value]);
return AnimatedBuilder(
animation: animationController,
builder: (context, _) => CircularProgressIndicator(
value: animationController.value,
color: Colors.white,
strokeWidth: 4,
backgroundColor: Colors.black.withOpacity(0.1),
),
);
}
),
),
Center(
child: HookBuilder(builder: (context) {
final animationController = useAnimationController(
duration: const Duration(milliseconds: 500),
initialValue: suspend ? 1.0 : 0.0
);
useMemoized(() {
if (suspend) {
animationController.forward();
} else {
animationController.reverse();
}
}, [suspend]);
return AnimatedIcon(
icon: AnimatedIcons.play_pause,
color: Colors.white,
progress: animationController,
);
}),
),
],
),
),
);
}

View File

@ -81,7 +81,7 @@ class SelectController extends GetxController {
enName: 'artist',
vImage: 'btn_male_pic_artist',
hImage: 'pic_male_artist',
selected: true,
selected: false,
enable: true,
));
occupations.add(Occupation(
@ -156,7 +156,7 @@ class SelectController extends GetxController {
enName: 'artist',
vImage: 'btn_female_pic_artist',
hImage: 'pic_female_artist',
selected: true,
selected: false,
enable: true,
));
occupations.add(Occupation(

View File

@ -4,23 +4,25 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class AnimatedHorizonColumnWidget extends HookWidget {
final List<Widget> children;
class OccupationListWidget extends HookWidget {
final VoidCallback? onDone;
const AnimatedHorizonColumnWidget({
const OccupationListWidget({
super.key,
required this.children,
required this.keyBuilder,
this.onDone,
});
final List<Widget> children;
final Object Function(int index) keyBuilder;
@override
Widget build(BuildContext context) {
final displayIndex = useState(0);
final visible = useState(false);
useMemoized(() async {
await Future.delayed(const Duration(milliseconds: 300));
visible.value = true;
});
return Row(
children: [
...children.mapIndexed((index, child) => AnimatedVisibilityWidget(
@ -30,16 +32,7 @@ class AnimatedHorizonColumnWidget extends HookWidget {
duration: const Duration(milliseconds: 500),
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isVisible: index <= displayIndex.value,
isInitAnimated: index == 0,
onDone: (visible) {
if (visible) {
displayIndex.value = displayIndex.value + 1;
if (displayIndex.value == children.length) {
onDone?.call();
}
}
},
isVisible: visible.value,
child: Padding(
padding: EdgeInsets.only(
left: index == 0 ? 0 : 16.h,

View File

@ -24,9 +24,15 @@ class SelectView extends GetView<SelectController> {
child: Obx(
() => Scaffold(
backgroundColor: Colors.transparent,
body: controller.confirm.value
? buildConfirm(context)
: buildSelect(context),
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: KeyedSubtree(
key: ValueKey(controller.confirm.value),
child: controller.confirm.value
? buildConfirm(context)
: buildSelect(context),
),
),
),
),
),
@ -75,7 +81,7 @@ class SelectView extends GetView<SelectController> {
Obx(
() => AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: AnimatedHorizonColumnWidget(
child: OccupationListWidget(
key: ValueKey(controller.selectOccupations.first.value.name ?? ''),
keyBuilder: (index) => controller.selectOccupations[index].value.name ?? '',
children: controller.selectOccupations.map((t) {
@ -204,25 +210,27 @@ class SelectView extends GetView<SelectController> {
}
Widget buildSelectChange(BuildContext context) {
return GestureDetector(
onTap: () async {
await controller.change();
},
child: Padding(
padding: REdgeInsets.only(left: 6),
child: Container(
width: 72.w,
height: 364.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectChange,
fit: BoxFit.fill,
return _ShowUp(
child: GestureDetector(
onTap: () async {
await controller.change();
},
child: Padding(
padding: REdgeInsets.only(left: 6),
child: Container(
width: 72.w,
height: 364.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectChange,
fit: BoxFit.fill,
),
),
),
child: Center(
child: Text(
'换一批',
style: TextStyles.mediumColorShadow16_032,
child: Center(
child: Text(
'换一批',
style: TextStyles.mediumColorShadow16_032,
),
),
),
),
@ -231,53 +239,55 @@ class SelectView extends GetView<SelectController> {
}
Widget buildConfirm(BuildContext context) {
return Obx(
() => Stack(
children: [
Positioned(
left: 90.w,
top: 62.h,
child: Container(
width: 999.w,
height: 558.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectBgBorder,
return _ShowUp(
child: Obx(
() => Stack(
children: [
Positioned(
left: 90.w,
top: 62.h,
child: Container(
width: 999.w,
height: 558.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectBgBorder,
fit: BoxFit.fill,
),
),
padding: REdgeInsets.only(
top: 13.0, left: 13.0, bottom: 10.0, right: 16.0),
child: LoadAssetImage(
'select/${controller.selectOccupation.value!.hImage!}',
height: 534.h,
width: 971.w,
fit: BoxFit.fill,
),
),
padding: REdgeInsets.only(
top: 13.0, left: 13.0, bottom: 10.0, right: 16.0),
child: LoadAssetImage(
'select/${controller.selectOccupation.value!.hImage!}',
height: 534.h,
width: 971.w,
fit: BoxFit.fill,
),
),
),
Positioned(
top: 64.h,
left: 363.w,
child: Container(
width: 450.w,
height: 61.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectTitle2,
fit: BoxFit.fill,
Positioned(
top: 64.h,
left: 363.w,
child: Container(
width: 450.w,
height: 61.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectTitle2,
fit: BoxFit.fill,
),
),
),
child: Center(
child: Text(
controller.confirmTitle.value,
style: TextStyles.boldWhiteShadow34_200,
child: Center(
child: Text(
controller.confirmTitle.value,
style: TextStyles.boldWhiteShadow34_200,
),
),
),
),
),
buildConfirmBtn(context, controller.selectOccupation.value!.name!),
],
buildConfirmBtn(context, controller.selectOccupation.value!.name!),
],
),
),
);
}

View File

@ -193,18 +193,28 @@ class InputWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
value == controller.selectedGender.value
? Images.selectPre
: Images.selectDefault,
Stack(
children: [
Images.selectDefault,
AnimatedVisibilityWidget(
animationWidgetBuilder: AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isVisible: value == controller.selectedGender.value,
child: Images.selectPre,
),
],
),
const RSizedBox(
width: 10,
),
Text(
name,
textAlign: TextAlign.center,
AnimatedDefaultTextStyle(
duration: kThemeAnimationDuration,
style: value == controller.selectedGender.value
? TextStyles.mediumWhite21_024
: TextStyles.mediumColor21,
child: Text(
name,
textAlign: TextAlign.center,
),
)
],
),
@ -217,7 +227,8 @@ class InputWidget extends StatelessWidget {
targetContext: null,
targetBuilder: (Offset targetOffset, Size targetSize) =>
Offset(588.w, 330.h),
nonAnimationTypes: [SmartNonAnimationType.maskClose_nonAnimation],
maskColor: Colors.transparent,
animationType: SmartAnimationType.centerFade_otherSlide,
onDismiss: () {
controller.pullStatus.value = 'down';
var formatter = DateFormat('yyyy-MM-dd');

View File

@ -137,6 +137,7 @@ class PartnerWidget extends HookWidget {
visible: isDialogShown.value,
child: AnimatedTextKit(
totalRepeatCount: 1,
pause: Duration.zero,
animatedTexts: [
TypewriterAnimatedText(
'${controller.textController.text}你好! 我是一只天马。我们天马族一直生活在这里。与探梦者为伴。接下来让我来做你探索的伙伴吧。',

View File

@ -50,6 +50,7 @@ class SplashView extends StatelessWidget {
child: Center(
child: AnimatedVisibilityWidget(
isVisible: isStoryShown.value,
animationWidgetBuilder: AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
child: IgnorePointer(
ignoring: !isStoryShown.value,
child: SwipeNextPageHandler(

View File

@ -95,8 +95,8 @@ class _Background extends StatelessWidget {
children: [
Positioned(
top: 0 - animationValue + 1,
left: -2,
right: 2,
left: 2,
right: -2,
child: Container(
width: constraint.maxWidth,
height: constraint.maxHeight,

View File

@ -280,6 +280,15 @@ class TextStyles {
fontWeight: FontWeight.bold,
shadows: [Shadows.txtShadow111],
);
static TextStyle boldWhiteShadow12_111 = TextStyle(
fontSize: Dimens.font_sp12.sp,
color: Colors.white,
fontFamily: 'alph-b',
fontWeight: FontWeight.bold,
shadows: [Shadows.txtShadow111_1],
);
static TextStyle boldWhiteShadow14_111 = TextStyle(
fontSize: Dimens.font_sp14.sp,
color: Colors.white,

View File

@ -33,11 +33,14 @@ class AnimatedColumnWidget extends HookWidget {
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isVisible: index <= displayIndex.value,
onDone: (visible) {
isInitAnimated: index == 0,
onDone: (visible) async {
if (visible) {
displayIndex.value = displayIndex.value + 1;
if (displayIndex.value == children.length) {
if (displayIndex.value == children.length - 1) {
onDone?.call();
} else {
await Future.delayed(const Duration(milliseconds: 500));
displayIndex.value = displayIndex.value + 1;
}
}
},