feat(mobile): redesign guide pages with fullscreen background images

向导页重新设计:

1. 页面1-4 改为全屏背景图片布局
   - 移除 SafeArea,图片延伸到状态栏
   - 移除文字标题和副标题(文字设计在图片中)
   - 仅保留底部页面指示器(白色圆点)

2. 页面5(欢迎加入页)也改为全屏背景图片
   - 添加渐变遮罩(30%~60%黑色)提高可读性
   - 表单区域改为透明背景
   - 所有文字、输入框、单选按钮改为白色系
   - 退出按钮文字从"退出 Exit"改为"退出"

3. 添加5张向导页背景图片
   - guide_1.jpg ~ guide_4.jpg: 介绍页背景
   - guide_5.png: 欢迎加入页背景

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-09 17:44:38 -08:00
parent 53320df220
commit 07448b381b
6 changed files with 223 additions and 171 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@ -38,28 +38,34 @@ class _GuidePageState extends ConsumerState<GuidePage> {
final PageController _pageController = PageController(); final PageController _pageController = PageController();
int _currentPage = 0; int _currentPage = 0;
// 1-4 // 1-5 (5)
// pngjpgwebp
final List<GuidePageData> _guidePages = const [ final List<GuidePageData> _guidePages = const [
GuidePageData( GuidePageData(
imagePath: 'assets/images/guide_1.png', imagePath: 'assets/images/guide_1.jpg',
title: '认种一棵榴莲树\n拥有真实RWA资产', title: '认种一棵榴莲树\n拥有真实RWA资产',
subtitle: '绑定真实果园20年收益让区块链与农业完美结合', subtitle: '绑定真实果园20年收益让区块链与农业完美结合',
), ),
GuidePageData( GuidePageData(
imagePath: 'assets/images/guide_2.png', imagePath: 'assets/images/guide_2.jpg',
title: '认种即可开启算力\n自动挖矿持续收益', title: '认种即可开启算力\n自动挖矿持续收益',
subtitle: '每一棵树都对应真实资产注入,为算力提供真实价值支撑', subtitle: '每一棵树都对应真实资产注入,为算力提供真实价值支撑',
), ),
GuidePageData( GuidePageData(
imagePath: 'assets/images/guide_3.png', imagePath: 'assets/images/guide_3.jpg',
title: '分享链接\n获得团队算力与收益', title: '分享链接\n获得团队算力与收益',
subtitle: '真实认种数据透明可信 · 团队越大算力越强', subtitle: '真实认种数据透明可信 · 团队越大算力越强',
), ),
GuidePageData( GuidePageData(
imagePath: 'assets/images/guide_4.png', imagePath: 'assets/images/guide_4.jpg',
title: 'MPC多方安全\n所有地址与收益可审计', title: 'MPC多方安全\n所有地址与收益可审计',
subtitle: '你的资产 · 安全透明 · 不可被篡改', subtitle: '你的资产 · 安全透明 · 不可被篡改',
), ),
GuidePageData(
imagePath: 'assets/images/guide_5.png',
title: '欢迎加入',
subtitle: '创建账号前的最后一步 · 请选择是否有推荐人',
),
]; ];
@override @override
@ -99,8 +105,7 @@ class _GuidePageState extends ConsumerState<GuidePage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: SafeArea( body: PageView.builder(
child: PageView.builder(
controller: _pageController, controller: _pageController,
onPageChanged: _onPageChanged, onPageChanged: _onPageChanged,
itemCount: 5, // 4 + 1 itemCount: 5, // 4 + 1
@ -112,72 +117,41 @@ class _GuidePageState extends ConsumerState<GuidePage> {
} }
}, },
), ),
),
); );
} }
/// (1-4) /// (1-4) -
Widget _buildGuidePage(GuidePageData data, int index) { Widget _buildGuidePage(GuidePageData data, int index) {
return Padding( return Stack(
padding: EdgeInsets.symmetric(horizontal: 24.w), fit: StackFit.expand,
child: Column(
children: [ children: [
SizedBox(height: 64.h), //
// if (data.imagePath != null)
Expanded( Image.asset(
flex: 5,
child: Container(
width: 312.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r),
color: const Color(0xFFFFF8E7),
),
child: data.imagePath != null
? ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: Image.asset(
data.imagePath!, data.imagePath!,
fit: BoxFit.cover, fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
return _buildPlaceholderImage(index); return Container(
color: const Color(0xFFFFF8E7),
child: _buildPlaceholderImage(index),
);
}, },
),
) )
: _buildPlaceholderImage(index), else
Container(
color: const Color(0xFFFFF8E7),
child: _buildPlaceholderImage(index),
), ),
//
Positioned(
left: 0,
right: 0,
bottom: 80.h,
child: _buildPageIndicator(),
), ),
SizedBox(height: 48.h),
//
Text(
data.title,
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.w700,
height: 1.33,
color: const Color(0xFF292524),
),
textAlign: TextAlign.center,
),
SizedBox(height: 16.h),
//
Padding(
padding: EdgeInsets.symmetric(horizontal: 24.w),
child: Text(
data.subtitle,
style: TextStyle(
fontSize: 14.sp,
height: 1.43,
color: const Color(0xFF57534E),
),
textAlign: TextAlign.center,
),
),
SizedBox(height: 48.h),
//
_buildPageIndicator(),
SizedBox(height: 80.h),
], ],
),
); );
} }
@ -223,10 +197,12 @@ class _GuidePageState extends ConsumerState<GuidePage> {
return _WelcomePageContent( return _WelcomePageContent(
onNext: _goToOnboarding, onNext: _goToOnboarding,
onExit: _exitApp, // 退 onExit: _exitApp, // 退
backgroundImage: _guidePages[4].imagePath,
pageIndicator: _buildPageIndicator(),
); );
} }
/// /// (使)
Widget _buildPageIndicator() { Widget _buildPageIndicator() {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -239,8 +215,8 @@ class _GuidePageState extends ConsumerState<GuidePage> {
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: isActive color: isActive
? const Color(0xFF8E794A) ? Colors.white
: const Color(0xFFEAE0CD), : Colors.white.withValues(alpha: 0.4),
), ),
); );
}), }),
@ -252,10 +228,14 @@ class _GuidePageState extends ConsumerState<GuidePage> {
class _WelcomePageContent extends ConsumerStatefulWidget { class _WelcomePageContent extends ConsumerStatefulWidget {
final VoidCallback onNext; final VoidCallback onNext;
final VoidCallback onExit; final VoidCallback onExit;
final String? backgroundImage;
final Widget pageIndicator;
const _WelcomePageContent({ const _WelcomePageContent({
required this.onNext, required this.onNext,
required this.onExit, required this.onExit,
this.backgroundImage,
required this.pageIndicator,
}); });
@override @override
@ -405,6 +385,41 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(), onTap: () => FocusScope.of(context).unfocus(),
child: Stack(
fit: StackFit.expand,
children: [
//
if (widget.backgroundImage != null)
Image.asset(
widget.backgroundImage!,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
errorBuilder: (context, error, stackTrace) {
return Container(
color: const Color(0xFFFFF8E7),
);
},
)
else
Container(
color: const Color(0xFFFFF8E7),
),
//
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withValues(alpha: 0.3),
Colors.black.withValues(alpha: 0.6),
],
),
),
),
//
SafeArea(
child: LayoutBuilder( child: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
return SingleChildScrollView( return SingleChildScrollView(
@ -421,28 +436,34 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
Align( Align(
alignment: Alignment.topRight, alignment: Alignment.topRight,
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 32.h), padding: EdgeInsets.only(top: 16.h),
child: GestureDetector( child: GestureDetector(
onTap: widget.onExit, onTap: widget.onExit,
child: Text( child: Text(
'退出 Exit', '退出',
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: const Color(0xFFA99F93), color: Colors.white.withValues(alpha: 0.8),
), ),
), ),
), ),
), ),
), ),
SizedBox(height: 80.h), SizedBox(height: 60.h),
// //
Text( Text(
'欢迎加入', '欢迎加入',
style: TextStyle( style: TextStyle(
fontSize: 24.sp, fontSize: 28.sp,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
height: 1.33, height: 1.33,
color: const Color(0xFF6F6354), color: Colors.white,
shadows: [
Shadow(
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 4,
),
],
), ),
), ),
SizedBox(height: 12.h), SizedBox(height: 12.h),
@ -452,34 +473,49 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
style: TextStyle( style: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
height: 1.43, height: 1.43,
color: const Color(0xFFA99F93), color: Colors.white.withValues(alpha: 0.9),
shadows: [
Shadow(
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 4,
),
],
), ),
), ),
SizedBox(height: 48.h), SizedBox(height: 48.h),
// // ()
_buildReferrerOptions(), _buildReferrerOptions(),
const Spacer(), const Spacer(),
//
widget.pageIndicator,
SizedBox(height: 24.h),
// //
GestureDetector( GestureDetector(
onTap: _canProceed ? _saveReferralCodeAndProceed : null, onTap: _canProceed ? _saveReferralCodeAndProceed : null,
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 16.h), padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration(
color: _canProceed
? const Color(0xFFD4A84B)
: Colors.white.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(12.r),
),
child: Text( child: Text(
'下一步 (创建账号)', '下一步 (创建账号)',
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w600,
height: 1.5, height: 1.5,
color: _canProceed color: _canProceed
? const Color(0xFFD4A84B) // - ? Colors.white
: const Color(0xFFCCC5B9), // - : Colors.white.withValues(alpha: 0.6),
), ),
textAlign: TextAlign.right, textAlign: TextAlign.center,
), ),
), ),
), ),
SizedBox(height: 48.h), SizedBox(height: 32.h),
], ],
), ),
), ),
@ -488,10 +524,13 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
); );
}, },
), ),
),
],
),
); );
} }
/// /// ()
Widget _buildReferrerOptions() { Widget _buildReferrerOptions() {
return Column( return Column(
children: [ children: [
@ -511,7 +550,13 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
height: 1.5, height: 1.5,
color: const Color(0xFF6F6354), color: Colors.white,
shadows: [
Shadow(
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 4,
),
],
), ),
), ),
], ],
@ -522,11 +567,11 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
if (_hasReferrer) if (_hasReferrer)
Container( Container(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w),
decoration: const BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
bottom: BorderSide( bottom: BorderSide(
width: 1, width: 1,
color: Color(0xFFEAE1D2), color: Colors.white.withValues(alpha: 0.5),
), ),
), ),
), ),
@ -539,7 +584,7 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
hintText: '请输入推荐码 / 序列号', hintText: '请输入推荐码 / 序列号',
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: const Color(0xFFA99F93), color: Colors.white.withValues(alpha: 0.6),
), ),
border: InputBorder.none, border: InputBorder.none,
isDense: true, isDense: true,
@ -547,8 +592,9 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
), ),
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
color: const Color(0xFF6F6354), color: Colors.white,
), ),
cursorColor: Colors.white,
), ),
), ),
// //
@ -559,7 +605,7 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
child: Icon( child: Icon(
Icons.camera_alt_outlined, Icons.camera_alt_outlined,
size: 20.sp, size: 20.sp,
color: const Color(0xFFA99F93), color: Colors.white.withValues(alpha: 0.8),
), ),
), ),
), ),
@ -583,7 +629,13 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
height: 1.5, height: 1.5,
color: const Color(0xFF6F6354), color: Colors.white,
shadows: [
Shadow(
color: Colors.black.withValues(alpha: 0.5),
blurRadius: 4,
),
],
), ),
), ),
], ],
@ -593,7 +645,7 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
); );
} }
/// /// ()
Widget _buildRadio(bool isSelected) { Widget _buildRadio(bool isSelected) {
return Container( return Container(
width: 20.w, width: 20.w,
@ -603,8 +655,8 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
border: Border.all( border: Border.all(
width: isSelected ? 6.w : 2.w, width: isSelected ? 6.w : 2.w,
color: isSelected color: isSelected
? const Color(0xFF2563EB) ? Colors.white
: const Color(0xFFA99F93), : Colors.white.withValues(alpha: 0.5),
), ),
), ),
); );