#请添加图片描述

个人中心是App的"我的"页面,用户可以在这里查看自己的信息、访问各种功能入口。今天来实现家具购买记录App的个人中心页面,包括用户头像、统计数据、功能菜单三个部分。

做个人中心的时候,我参考了很多App的设计。发现大部分App的个人中心都是顶部放用户信息,中间放统计数据,下面放功能菜单。这种布局用户已经很熟悉了,所以我也采用这种结构。

页面整体结构

个人中心用 StatelessWidget 实现,因为这个页面主要是展示和导航,不需要管理复杂状态。

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import '../../app/routes/app_routes.dart';

class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});

导入了四个依赖:Material 组件库、屏幕适配工具、GetX 路由、自定义路由常量。这些是这个页面需要用到的全部依赖。

StatelessWidget 而不是 StatefulWidget,是因为这个页面没有需要动态变化的状态。所有数据都是从外部获取的,页面本身只负责展示。

页面主体布局

build 方法里用 SingleChildScrollView 包裹内容,这样内容多了可以滚动。

  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFFAF8F5),
      body: SingleChildScrollView(
        child: Column(
          children: [
            _buildHeader(),
            _buildStatsRow(),
            SizedBox(height: 16.h),

注意这个页面没有 AppBar,因为个人中心通常是底部导航的一个 tab,不需要返回按钮。顶部的用户信息区域会延伸到状态栏,形成沉浸式效果。

背景色还是用统一的米白色 0xFFFAF8F5,和其他页面保持一致。

功能菜单分组

功能菜单分成三组:家具管理、财务管理、其他。每组之间用 SizedBox 隔开。

            _buildMenuSection('家具管理', [
              _buildMenuItem(Icons.chair, '我的家具', () => Get.toNamed(AppRoutes.furnitureList)),
              _buildMenuItem(Icons.room, '房间管理', () => Get.toNamed(AppRoutes.roomList)),
              _buildMenuItem(Icons.category, '分类管理', () => Get.toNamed(AppRoutes.categoryManage)),
              _buildMenuItem(Icons.business, '品牌管理', () => Get.toNamed(AppRoutes.brandManage)),
            ]),
            SizedBox(height: 12.h),

家具管理组包含四个入口:我的家具、房间管理、分类管理、品牌管理。这些都是和家具直接相关的功能。

每个菜单项用 _buildMenuItem 方法构建,传入图标、标题、点击回调。点击后用 GetX 的路由跳转到对应页面。

财务管理分组

财务管理组包含购买记录、预算管理、商家管理三个入口。

            _buildMenuSection('财务管理', [
              _buildMenuItem(Icons.receipt_long, '购买记录', () => Get.toNamed(AppRoutes.purchaseRecord)),
              _buildMenuItem(Icons.account_balance_wallet, '预算管理', () => Get.toNamed(AppRoutes.budgetManage)),
              _buildMenuItem(Icons.store, '商家管理', () => Get.toNamed(AppRoutes.storeManage)),
            ]),
            SizedBox(height: 12.h),

这三个功能都和钱相关:购买记录看花了多少钱,预算管理控制花钱上限,商家管理记录在哪买的。

图标选择上,购买记录用收据图标,预算管理用钱包图标,商家管理用商店图标。图标要能直观表达功能含义。

其他功能分组

其他分组放一些辅助功能:保修管理、数据备份、设置、关于我们。

            _buildMenuSection('其他', [
              _buildMenuItem(Icons.security, '保修管理', () => Get.toNamed(AppRoutes.warrantyManage)),
              _buildMenuItem(Icons.cloud_upload, '数据备份', () => Get.toNamed(AppRoutes.dataBackup)),
              _buildMenuItem(Icons.settings, '设置', () => Get.toNamed(AppRoutes.settings)),
              _buildMenuItem(Icons.info_outline, '关于我们', () => Get.toNamed(AppRoutes.about)),
            ]),
            SizedBox(height: 30.h),
          ],
        ),
      ),
    );
  }

保修管理虽然也和家具相关,但它更偏向售后服务,所以放在其他分组。数据备份和设置是工具类功能,关于我们是信息展示。

最后加了 30 的底部间距,防止内容贴着屏幕底部,也给底部导航栏留出空间。

顶部用户信息区域

_buildHeader 方法构建顶部的用户信息区域,用渐变背景。

  Widget _buildHeader() {
    return Container(
      padding: EdgeInsets.only(top: 60.h, bottom: 24.h),
      decoration: const BoxDecoration(
        gradient: LinearGradient(
          colors: [Color(0xFF8B4513), Color(0xFFA0522D)]
        ),
      ),

padding 的 top 设置为 60,是为了避开状态栏。不同设备状态栏高度不一样,60 是一个比较安全的值。

渐变色从深棕色到浅棕色,和 AppBar 的颜色一致,保持整体风格统一。

用户头像和昵称

头像用 CircleAvatar 组件,里面放一个人物图标。昵称和签名用白色文字显示。

      child: Column(
        children: [
          CircleAvatar(
            radius: 40.r,
            backgroundColor: Colors.white,
            child: Icon(Icons.person, size: 40.sp, color: const Color(0xFF8B4513)),
          ),
          SizedBox(height: 12.h),
          Text('家居达人', style: TextStyle(
            color: Colors.white, 
            fontSize: 20.sp, 
            fontWeight: FontWeight.bold
          )),
          SizedBox(height: 4.h),
          Text('记录美好家居生活', style: TextStyle(
            color: Colors.white70, 
            fontSize: 13.sp
          )),
        ],
      ),
    );
  }

头像半径 40,白色背景,里面的图标用主题棕色。这样头像在渐变背景上很醒目。

昵称"家居达人"用白色加粗显示,是视觉焦点。签名"记录美好家居生活"用半透明白色,作为补充说明。

实际项目中,这些信息应该从用户数据里读取,这里先用固定值展示效果。

统计数据行

_buildStatsRow 方法构建统计数据区域,显示家具数量、房间数、总价值。

  Widget _buildStatsRow() {
    return Container(
      margin: EdgeInsets.all(16.w),
      padding: EdgeInsets.all(16.w),
      decoration: BoxDecoration(
        color: Colors.white, 
        borderRadius: BorderRadius.circular(16.r)
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          _buildStatItem('48', '家具'),
          Container(width: 1, height: 40.h, color: Colors.grey[200]),
          _buildStatItem('6', '房间'),
          Container(width: 1, height: 40.h, color: Colors.grey[200]),
          _buildStatItem('¥86.5k', '总价值'),
        ],
      ),
    );
  }

三个统计项用竖线分隔,竖线用 Container 实现,宽度 1,高度 40,颜色是浅灰色。

白色卡片加圆角,和背景形成对比。margin 和 padding 都是 16,内外间距一致。

spaceAround 让三个统计项均匀分布,竖线自然就在它们中间了。

单个统计项

_buildStatItem 方法构建单个统计项,数值在上,标签在下。

  Widget _buildStatItem(String value, String label) {
    return Column(
      children: [
        Text(value, style: TextStyle(
          fontSize: 20.sp, 
          fontWeight: FontWeight.bold, 
          color: const Color(0xFF8B4513)
        )),
        SizedBox(height: 4.h),
        Text(label, style: TextStyle(
          color: Colors.grey[600], 
          fontSize: 12.sp
        )),
      ]
    );
  }

数值用主题棕色加粗显示,字号 20,是整个卡片的视觉焦点。标签用灰色小字,起说明作用。

这种上下结构的统计项很常见,用户一眼就能看懂。数值大、标签小,主次分明。

菜单分组容器

_buildMenuSection 方法构建菜单分组的容器,包含标题和菜单项列表。

  Widget _buildMenuSection(String title, List<Widget> items) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 16.w),
      decoration: BoxDecoration(
        color: Colors.white, 
        borderRadius: BorderRadius.circular(16.r)
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: EdgeInsets.all(16.w),
            child: Text(title, style: TextStyle(
              fontSize: 14.sp, 
              fontWeight: FontWeight.bold, 
              color: const Color(0xFF5D4037)
            )),
          ),
          ...items,
        ],
      ),
    );
  }

容器只有左右 margin,没有上下 margin,这样多个分组之间的间距由外部的 SizedBox 控制。

标题用深棕色加粗,和设置页面的分组标题样式一致。...items 展开菜单项列表。

白色背景加 16 的圆角,和统计卡片样式统一。整个页面的卡片都用这个样式。

单个菜单项

_buildMenuItem 方法构建单个菜单项,左边图标,中间标题,右边箭头。

  Widget _buildMenuItem(IconData icon, String title, VoidCallback onTap) {
    return InkWell(
      onTap: onTap,
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 14.h),
        child: Row(
          children: [
            Icon(icon, color: const Color(0xFF8B4513), size: 22.sp),
            SizedBox(width: 14.w),
            Expanded(child: Text(title, style: TextStyle(fontSize: 14.sp))),
            Icon(Icons.chevron_right, color: Colors.grey[400], size: 20.sp),
          ],
        ),
      ),
    );
  }
}

InkWell 包裹整个区域,点击有水波纹效果。padding 设置水平 16、垂直 14,让点击区域足够大。

图标用主题棕色,大小 22。标题用 Expanded 包裹,占满中间空间。右边箭头用灰色,表示可以点击进入。

这种三段式布局是菜单项的标准样式,用户很熟悉,不需要学习成本。

图标选择原则

给每个菜单项选图标的时候,要考虑图标能不能直观表达功能含义:

我的家具用椅子图标 Icons.chair,直接表示家具。

房间管理用房间图标 Icons.room,表示房间。

分类管理用分类图标 Icons.category,表示分类。

品牌管理用商业图标 Icons.business,表示品牌/公司。

购买记录用收据图标 Icons.receipt_long,表示购买凭证。

预算管理用钱包图标 Icons.account_balance_wallet,表示钱。

商家管理用商店图标 Icons.store,表示商家。

保修管理用安全图标 Icons.security,表示保障。

数据备份用云上传图标 Icons.cloud_upload,表示备份到云端。

设置用齿轮图标 Icons.settings,这是设置的通用图标。

关于我们用信息图标 Icons.info_outline,表示信息说明。

沉浸式状态栏

这个页面没有 AppBar,顶部的渐变区域直接延伸到状态栏。要实现这个效果,需要在 main.dart 里设置状态栏透明。

// 在 main.dart 的 main 函数里添加
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
  statusBarColor: Colors.transparent,
));

这样状态栏就会变成透明的,渐变背景可以延伸上去。状态栏的图标颜色会自动根据背景调整。

不过要注意,顶部内容要留出状态栏的高度,不然会被状态栏遮挡。这就是为什么 _buildHeader 的 top padding 设置为 60。

数据来源说明

目前页面上的数据都是写死的:48 件家具、6 个房间、86.5k 总价值。实际项目中这些数据应该从数据库查询。

// 示例:从数据库获取统计数据
// final furnitureCount = await db.getFurnitureCount();
// final roomCount = await db.getRoomCount();
// final totalValue = await db.getTotalValue();

可以用 GetX 的控制器来管理这些数据,页面加载时查询数据库,然后更新 UI。

用户昵称和签名也应该从用户信息里读取,如果有登录功能的话。

点击反馈优化

InkWell 的水波纹效果是 Material Design 的标准反馈,但有时候可能想要其他效果。

// 如果想要缩放效果,可以用 GestureDetector 配合 AnimatedScale
// 如果想要高亮效果,可以用 InkWell 的 highlightColor 属性
// 如果想要自定义效果,可以用 GestureDetector 配合自定义动画

目前用默认的水波纹效果就够了,简单而且用户熟悉。

页面跳转方式

所有菜单项点击后都用 Get.toNamed 跳转,这是 GetX 的命名路由跳转方式。

Get.toNamed(AppRoutes.furnitureList)

AppRoutes 是我们定义的路由常量类,里面定义了所有页面的路由路径。用常量而不是字符串,可以避免拼写错误,IDE 也能提供自动补全。

如果需要传参数,可以用 arguments 参数:

Get.toNamed(AppRoutes.furnitureDetail, arguments: {'id': 123})

布局适配要点

这个页面用了很多 flutter_screenutil 的适配方法:

.w 用于宽度相关的值,比如 margin、padding 的水平方向。

.h 用于高度相关的值,比如 padding 的垂直方向、SizedBox 的高度。

.sp 用于字号,会根据系统字体设置缩放。

.r 用于圆角,保持比例协调。

这样在不同尺寸的设备上,页面布局都能保持合理的比例。

小结

个人中心页面的实现主要是布局和导航,把用户信息、统计数据、功能菜单组织在一起。用 StatelessWidget 实现,因为不需要管理复杂状态。

代码组织上,把每个部分抽成独立方法:_buildHeader_buildStatsRow_buildMenuSection_buildMenuItem。这样主 build 方法很清晰,修改某个部分也很方便。

个人中心是用户使用频率很高的页面,所以功能入口的分类和排序很重要。把常用的放前面,相关的放一组,用户找起来就方便。

下一篇会讲关于我们页面的实现,那个页面主要是展示App信息和一些链接入口,敬请期待。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐