keyboard_tutorial_page.dart 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:get/get.dart';
  4. import 'package:keyboard/base/base_page.dart';
  5. import 'package:keyboard/resource/colors.gen.dart';
  6. import 'package:keyboard/resource/string.gen.dart';
  7. import 'package:keyboard/router/app_pages.dart';
  8. import 'package:lottie/lottie.dart';
  9. import '../../resource/assets.gen.dart';
  10. import '../../utils/status_bar_util.dart';
  11. import '../../widget/app_lifecycle_widget.dart';
  12. import '../../widget/gradient_btn.dart';
  13. import 'keyboard_tutorial_controller.dart';
  14. /// 键盘使用教程-引导页
  15. class KeyboardTutorialPage extends BasePage<KeyboardTutorialController> {
  16. const KeyboardTutorialPage({super.key});
  17. static start() {
  18. Get.toNamed(RoutePath.keyboardTutorial);
  19. }
  20. @override
  21. bool immersive() {
  22. // 开启沉浸式
  23. return true;
  24. }
  25. @override
  26. backgroundColor() {
  27. return Color(0xFFF6F5FA);
  28. }
  29. @override
  30. Widget buildBody(BuildContext context) {
  31. return Scaffold(
  32. backgroundColor: backgroundColor(),
  33. body: AppLifecycleWidget(
  34. onAppLifecycleCallback: (isForeground) {
  35. // 步骤都做完了,则跳转去键盘引导页
  36. if (controller.checkHasComplete()) {
  37. return;
  38. }
  39. // 未完成,则每次切换到前台时,重新检查设置,更新按钮状态
  40. if (isForeground) {
  41. controller.checkSetting();
  42. }
  43. },
  44. child: Stack(
  45. children: [
  46. // 头部
  47. Positioned(left: 0, top: 0, right: 0, child: _buildHeader()),
  48. // 状态栏和标题栏
  49. Positioned(
  50. left: 0,
  51. top: 0,
  52. right: 0,
  53. child: Column(
  54. mainAxisSize: MainAxisSize.min,
  55. children: [_buildStatusBar(), _buildTopBar()],
  56. ),
  57. ),
  58. // 内容,填充剩余部分
  59. Positioned.fill(
  60. top: 235.h + StatusBarUtil.getStatusBarHeight(Get.context!),
  61. left: 0,
  62. right: 0,
  63. child: Column(children: [_buildContent()]),
  64. ),
  65. // 底部按钮
  66. Positioned(
  67. left: 0,
  68. right: 0,
  69. bottom: 0,
  70. child: _buildBottomActionBtn(),
  71. ),
  72. ],
  73. ),
  74. ),
  75. );
  76. }
  77. /// 导航栏占位
  78. Widget _buildStatusBar() {
  79. // 导航栏高度
  80. double statusBarHeight = StatusBarUtil.getStatusBarHeight(Get.context!);
  81. return Container(height: statusBarHeight);
  82. }
  83. /// 顶部栏
  84. Widget _buildTopBar() {
  85. return Container(
  86. // 宽度撑满父组件
  87. width: double.infinity,
  88. height: kToolbarHeight,
  89. // 背景颜色
  90. color: Colors.transparent,
  91. // padding: EdgeInsets.symmetric(horizontal: 16.0),
  92. child: ConstrainedBox(
  93. // 设置宽度为无限大,撑满父组件,否则Stack获取不到高度,会报错
  94. constraints: BoxConstraints(minWidth: double.infinity),
  95. child: Stack(
  96. alignment: Alignment.center,
  97. children: [
  98. // 返回按钮
  99. Positioned(
  100. left: 16.w,
  101. child: GestureDetector(
  102. onTap: controller.clickBack,
  103. child: Assets.images.iconBlackBackArrow.image(
  104. width: 24.w,
  105. height: 24.h,
  106. ),
  107. ),
  108. ),
  109. // 跳过按钮
  110. Positioned(
  111. right: 16.w,
  112. child: GestureDetector(
  113. onTap: () {
  114. controller.clickSkip();
  115. },
  116. child: Text(
  117. StringName.skip,
  118. style: TextStyle(
  119. color: ColorName.black85,
  120. fontSize: 14.sp,
  121. fontWeight: FontWeight.w500,
  122. ),
  123. ),
  124. ),
  125. ),
  126. ],
  127. ),
  128. ),
  129. );
  130. }
  131. /// 头部布局
  132. Widget _buildHeader() {
  133. return SizedBox(
  134. width: double.infinity,
  135. height: 298.h,
  136. child: Stack(
  137. alignment: Alignment.center,
  138. children: [
  139. // 头像
  140. Positioned(
  141. top: 37.5.h,
  142. bottom: 86.5.h,
  143. child: Assets.images.iconKeyboardTutorialHeader.image(
  144. height: 174.h,
  145. fit: BoxFit.cover,
  146. ),
  147. ),
  148. // 蒙版
  149. Assets.images.bgKeyboardTutorialHeaderMask.image(
  150. width: double.infinity,
  151. height: double.infinity,
  152. ),
  153. // 提示语
  154. Positioned(
  155. bottom: 60.h,
  156. child: Assets.images.iconKeyboardTutorialHeaderSlogan.image(
  157. width: 200.w,
  158. height: 73.h,
  159. ),
  160. ),
  161. ],
  162. ),
  163. );
  164. }
  165. /// 内容
  166. Widget _buildContent() {
  167. return Expanded(child: Column(children: [_buildTutorialAnimation()]));
  168. }
  169. /// 键盘设置引导动画
  170. Widget _buildTutorialAnimation() {
  171. return Lottie.asset(
  172. Assets.anim.animKeyboardTutorialSetting,
  173. repeat: true,
  174. width: 340.w,
  175. );
  176. }
  177. /// 启用键盘按钮
  178. Widget _buildEnableKeyboard() {
  179. return Obx(() {
  180. return Container(
  181. margin: EdgeInsets.symmetric(horizontal: 50.w),
  182. child: GradientTextBtn(
  183. // 是否启用,这里UI设计上,未启用时要高亮按钮,所以要取反
  184. enable: !controller.isKeyboardEnable.value,
  185. StringName.tutorialEnableKeyboardStep,
  186. onPressed: () {
  187. // 已启用,不响应点击
  188. if (controller.isKeyboardEnable.value) {
  189. return;
  190. }
  191. // 去启用键盘
  192. controller.goEnableKeyboard();
  193. },
  194. ),
  195. );
  196. });
  197. }
  198. /// 悬浮球设置按钮
  199. Widget _buildFloatingBallActionBtn() {
  200. return Obx(() {
  201. bool isKeyboardEnable = controller.isKeyboardEnable.value;
  202. bool isFloatingWindowEnable = controller.isFloatingWindowEnable.value;
  203. // 启用了键盘,但悬浮窗权限未获取到,则高亮按钮
  204. bool isHighlightBtn = isKeyboardEnable && !isFloatingWindowEnable;
  205. return Container(
  206. margin: EdgeInsets.symmetric(horizontal: 50.w),
  207. child: GradientTextBtn(
  208. enable: isHighlightBtn,
  209. StringName.tutorialEnableFloatingBallStep,
  210. onPressed: () {
  211. // 已获取,不响应点击
  212. if (controller.isFloatingWindowEnable.value) {
  213. return;
  214. }
  215. // 去启用悬浮球
  216. controller.jumpFloatingWindowSetting();
  217. },
  218. ),
  219. );
  220. });
  221. }
  222. /// 底部操作按钮
  223. Widget _buildBottomActionBtn() {
  224. return Column(
  225. children: [
  226. // 启用键盘
  227. _buildEnableKeyboard(),
  228. SizedBox(height: 20.h),
  229. // 启用悬浮球
  230. _buildFloatingBallActionBtn(),
  231. // 距离底部一定距离
  232. SizedBox(height: 25.h),
  233. ],
  234. );
  235. }
  236. }