常量与不可变性实战:Flutter在鸿蒙应用中配置主题色常量


作者:付文龙(红目香薰)
仓库地址:https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com
引言
在Flutter开发中,常量与不可变性是构建高质量应用的重要基石。使用常量不仅可以提高代码的可读性和可维护性,还能带来显著的性能优化。特别是在鸿蒙平台上,合理地配置主题色常量对于打造一致的用户体验至关重要。
本章将深入探讨Dart中的常量声明机制和不可变性原则,通过一个实际的应用场景——在鸿蒙平台的Flutter应用中配置主题色常量——来展示这些特性的实际应用。
一、Dart中的常量声明
Dart提供了两种常量声明方式:const和final。虽然它们都表示不可修改的值,但在语义和使用场景上有重要区别。
1.1 const编译时常量
const声明的是编译时常量,其值必须在编译时确定。这意味着const变量的值在程序运行之前就已经固定,编译器可以对其进行优化。
const String platform = 'HarmonyOS';
const int maxUsers = 10000;
const double pi = 3.1415926;
const的特点
| 特性 | 说明 |
|---|---|
| 值确定时机 | 编译时 |
| 可修改性 | 不可修改 |
| 内存优化 | 多个相同const值共享内存 |
| 适用场景 | 固定不变的值,如配置参数、数学常量 |
const的使用场景
// 颜色常量
const Color primaryColor = Color(0xFF2196F3);
const Color backgroundColor = Color(0xFFF5F5F5);
// 字体大小常量
const double fontSizeLarge = 18.0;
const double fontSizeNormal = 16.0;
// 间距常量
const double spacingSmall = 8.0;
const double spacingMedium = 16.0;
// URL常量
const String apiBaseUrl = 'https://api.example.com';
const String imageBaseUrl = 'https://images.example.com';
// 字符串常量
const String appName = 'Flutter学习助手';
const String version = '1.0.0';
1.2 final运行时常量
final声明的是运行时常量,其值可以在运行时确定,但一旦赋值就不能再修改。
final String appName = loadAppName();
final Person currentUser = fetchCurrentUser();
final DateTime now = DateTime.now();
final的特点
| 特性 | 说明 |
|---|---|
| 值确定时机 | 运行时 |
| 可修改性 | 不可修改 |
| 内存优化 | 无特殊优化 |
| 适用场景 | 需要运行时计算的值 |
final的使用场景
// 从配置文件加载的值
final String appName = loadFromConfig('app_name');
// 从网络获取的数据
final Person currentUser = await api.getUser();
// 运行时计算的值
final DateTime appStartTime = DateTime.now();
// 通过构造函数传入的值
class UserProfile {
final String name;
final int age;
UserProfile({required this.name, required this.age});
}
1.3 const与final的对比
void main() {
// const:编译时确定,不可修改
const int constValue = 10;
// final:运行时确定,不可修改
final int finalValue = DateTime.now().second;
// const可以用于编译时常量表达式
const int doubledConst = constValue * 2;
// final不能用于编译时常量表达式
// const int doubledFinal = finalValue * 2; // 错误
print('const值: $constValue');
print('final值: $finalValue');
print('doubledConst值: $doubledConst');
}
1.4 const构造函数
在Flutter中,许多Widget都提供了const构造函数,使用const构造函数创建的Widget实例会被缓存,从而提高性能。
// 使用const构造函数
const Text('Hello World');
const Icon(Icons.home);
const SizedBox(height: 16);
// 非const构造函数
Text('Hello World'); // 每次创建新实例
性能对比:
| 构造方式 | 实例创建 | 内存占用 | 适用场景 |
|---|---|---|---|
| const构造函数 | 缓存复用 | 低 | 静态内容、频繁使用的Widget |
| 非const构造函数 | 每次新建 | 高 | 动态内容、一次性使用的Widget |
二、不可变性原则
不可变性是指对象在创建后其状态不能被改变。在Flutter开发中,遵循不可变性原则可以带来诸多好处。
2.1 不可变性的好处
2.1.1 线程安全
不可变对象天生是线程安全的,因为它们的状态不会改变,不需要进行同步处理。
// 不可变对象:线程安全
class ImmutablePerson {
final String name;
final int age;
const ImmutablePerson({required this.name, required this.age});
}
// 可变对象:需要同步处理
class MutablePerson {
String name;
int age;
MutablePerson({required this.name, required this.age});
}
2.1.2 更容易的状态管理
不可变对象使得状态变化更容易追踪,因为每次状态变化都会产生一个新的对象。
// 不可变状态
final Person person1 = Person(name: '张三', age: 28);
final Person person2 = person1.copyWith(age: 29);
// person1和person2是不同的对象
// 状态变化清晰可追踪
2.1.3 更好的性能
在Flutter中,Widget的重建依赖于状态变化的检测。不可变对象可以通过引用比较来快速判断是否需要重建。
// 使用const Widget避免不必要的重建
Widget build(BuildContext context) {
return const Center(
child: Text('标题'),
);
}
2.1.4 更安全的代码
不可变对象避免了意外的副作用,使代码更加健壮。
// 不可变列表
const List<String> tags = ['Flutter', 'Dart'];
// tags.add('HarmonyOS'); // 错误:const列表不可修改
// 可变列表
List<String> mutableTags = ['Flutter', 'Dart'];
mutableTags.add('HarmonyOS'); // 可以修改
2.2 实现不可变对象
在Dart中,实现不可变对象需要遵循以下规则:
- 所有字段使用
final修饰 - 提供
const构造函数(如果可能) - 不提供修改字段的方法
- 如果需要更新状态,提供
copyWith方法
class Person {
final String name;
final int age;
final String occupation;
final String gender;
final String email;
final String phone;
final String avatarUrl;
final List<String> socialAccounts;
final bool isOnline;
final String location;
final String bio;
const Person({
required this.name,
required this.age,
required this.occupation,
required this.gender,
required this.email,
required this.phone,
required this.avatarUrl,
required this.socialAccounts,
required this.isOnline,
required this.location,
required this.bio,
});
Person copyWith({
String? name,
int? age,
String? occupation,
String? gender,
String? email,
String? phone,
String? avatarUrl,
List<String>? socialAccounts,
bool? isOnline,
String? location,
String? bio,
}) {
return Person(
name: name ?? this.name,
age: age ?? this.age,
occupation: occupation ?? this.occupation,
gender: gender ?? this.gender,
email: email ?? this.email,
phone: phone ?? this.phone,
avatarUrl: avatarUrl ?? this.avatarUrl,
socialAccounts: socialAccounts ?? this.socialAccounts,
isOnline: isOnline ?? this.isOnline,
location: location ?? this.location,
bio: bio ?? this.bio,
);
}
}
2.3 不可变集合
Dart提供了不可变集合的创建方式:
// 不可变列表
const List<String> immutableList = ['张三', '李四', '王五'];
// 不可变映射
const Map<String, int> immutableMap = {'张三': 90, '李四': 85};
// 不可变集合
const Set<String> immutableSet = {'Flutter', 'Dart', 'HarmonyOS'};
// 通过unmodifiable创建不可变集合
List<String> mutableList = ['张三', '李四'];
List<String> unmodifiableList = List.unmodifiable(mutableList);
注意:即使使用const声明集合,如果集合元素是可变对象,仍然可能导致问题:
// 危险:const集合包含可变对象
const List<MutablePerson> people = [
MutablePerson(name: '张三', age: 28),
];
people[0].age = 29; // 可以修改!
// 安全:const集合包含不可变对象
const List<ImmutablePerson> safePeople = [
ImmutablePerson(name: '张三', age: 28),
];
// safePeople[0].age = 29; // 错误:age是final字段
三、配置应用主题色常量
在实际开发中,我们通常将应用的主题色、字体、间距等配置集中管理,便于统一修改和维护。
3.1 创建常量管理文件
创建一个专门的常量管理文件,将所有常量集中在一起:
import 'package:flutter/material.dart';
class AppColors {
static const Color primary = Color(0xFF2196F3);
static const Color primaryLight = Color(0xFF64B5F6);
static const Color primaryDark = Color(0xFF1976D2);
static const Color secondary = Color(0xFF4CAF50);
static const Color secondaryLight = Color(0xFF81C784);
static const Color secondaryDark = Color(0xFF388E3C);
static const Color accent = Color(0xFFFFC107);
static const Color accentLight = Color(0xFFFFD54F);
static const Color accentDark = Color(0xFFFFA000);
static const Color background = Color(0xFFF5F5F5);
static const Color surface = Color(0xFFFFFFFF);
static const Color error = Color(0xFFF44336);
static const Color textPrimary = Color(0xFF212121);
static const Color textSecondary = Color(0xFF757575);
static const Color textHint = Color(0xFF9E9E9E);
static const Color divider = Color(0xFFE0E0E0);
static const Color disabled = Color(0xFFBDBDBD);
static const Color shadow = Color(0x1F000000);
static const Color online = Color(0xFF4CAF50);
static const Color offline = Color(0xFF9E9E9E);
static const Color male = Color(0xFF2196F3);
static const Color female = Color(0xFFE91E63);
}
class AppFonts {
static const String family = 'Roboto';
static const double sizeExtraSmall = 10.0;
static const double sizeSmall = 12.0;
static const double sizeMedium = 14.0;
static const double sizeNormal = 16.0;
static const double sizeLarge = 18.0;
static const double sizeExtraLarge = 24.0;
static const double sizeTitle = 28.0;
static const double sizeHeading = 32.0;
}
class AppSpacing {
static const double xs = 4.0;
static const double sm = 8.0;
static const double md = 16.0;
static const double lg = 24.0;
static const double xl = 32.0;
static const double xxl = 48.0;
}
class AppRadius {
static const double sm = 4.0;
static const double md = 8.0;
static const double lg = 12.0;
static const double xl = 16.0;
static const double circular = 9999.0;
}
class AppDurations {
static const Duration instant = Duration(milliseconds: 100);
static const Duration fast = Duration(milliseconds: 200);
static const Duration normal = Duration(milliseconds: 300);
static const Duration slow = Duration(milliseconds: 500);
static const Duration long = Duration(seconds: 1);
}
class AppUrls {
static const String baseUrl = 'https://api.example.com';
static const String avatarUrl = 'https://api.example.com/avatar';
static const String userUrl = 'https://api.example.com/user';
}
class AppStrings {
static const String appName = 'Flutter学习助手';
static const String appVersion = '1.0.0';
static const String platform = 'HarmonyOS';
static const String titlePersonalInfo = '个人信息卡片';
static const String labelName = '姓名';
static const String labelAge = '年龄';
static const String labelOccupation = '职业';
static const String labelGender = '性别';
static const String labelEmail = '邮箱';
static const String labelPhone = '电话';
static const String labelLocation = '位置';
static const String labelBio = '个人简介';
static const String labelContact = '联系方式';
static const String labelSocialAccounts = '社交账号';
static const String hintName = '请输入姓名';
static const String hintAge = '请输入年龄';
static const String hintOccupation = '请输入职业';
static const String hintBio = '请输入个人简介';
static const String errorInvalidAge = '请输入有效的年龄';
static const String errorRequired = '此项不能为空';
static const String onlineText = '在线';
static const String offlineText = '离线';
static const String actionEdit = '编辑';
static const String actionSave = '保存';
static const String actionCancel = '取消';
}
3.2 在应用中使用常量
现在,我们可以在应用的各个地方使用这些常量:
import 'package:flutter/material.dart';
import 'package:harmonyos_study/constants/app_constants.dart';
class PersonalInfoApp extends StatelessWidget {
const PersonalInfoApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: AppStrings.appName,
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch(
primarySwatch: Colors.blue,
backgroundColor: AppColors.background,
),
primaryColor: AppColors.primary,
primaryColorDark: AppColors.primaryDark,
primaryColorLight: AppColors.primaryLight,
scaffoldBackgroundColor: AppColors.background,
cardColor: AppColors.surface,
textTheme: TextTheme(
titleLarge: TextStyle(
fontSize: AppFonts.sizeLarge,
fontWeight: FontWeight.bold,
color: AppColors.textPrimary,
),
bodyLarge: TextStyle(
fontSize: AppFonts.sizeNormal,
color: AppColors.textPrimary,
),
bodyMedium: TextStyle(
fontSize: AppFonts.sizeMedium,
color: AppColors.textSecondary,
),
),
),
home: const PersonalInfoPage(),
);
}
}
3.3 在Widget中使用常量
Widget _buildAvatarSection() {
return Center(
child: Stack(
children: [
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: AppColors.primaryLight.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppRadius.circular),
border: Border.all(
color: AppColors.primary,
width: 3,
),
),
child: Icon(
Icons.person,
size: 60,
color: AppColors.primary,
),
),
Positioned(
bottom: AppSpacing.xs,
right: AppSpacing.xs,
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: _currentPerson.isOnline ? AppColors.online : AppColors.offline,
borderRadius: BorderRadius.circular(AppRadius.circular),
border: Border.all(
color: AppColors.surface,
width: 2,
),
),
),
),
],
),
);
}
四、主题配置的最佳实践
4.1 遵循单一职责原则
将不同类型的常量分开管理,每个类负责一类常量:
// 颜色常量
class AppColors { ... }
// 字体常量
class AppFonts { ... }
// 间距常量
class AppSpacing { ... }
// 圆角常量
class AppRadius { ... }
// 字符串常量
class AppStrings { ... }
4.2 使用语义化命名
为常量使用语义化的名称,使其含义一目了然:
// 好的命名
static const Color primary = Color(0xFF2196F3);
static const Color textPrimary = Color(0xFF212121);
// 不好的命名
static const Color blueColor = Color(0xFF2196F3);
static const Color darkTextColor = Color(0xFF212121);
4.3 提供明暗主题支持
为应用提供明暗主题支持,提升用户体验:
class AppColors {
// 浅色主题颜色
static const Color lightBackground = Color(0xFFF5F5F5);
static const Color lightSurface = Color(0xFFFFFFFF);
static const Color lightTextPrimary = Color(0xFF212121);
// 深色主题颜色
static const Color darkBackground = Color(0xFF121212);
static const Color darkSurface = Color(0xFF1E1E1E);
static const Color darkTextPrimary = Color(0xFFFFFFFF);
}
class AppTheme {
static ThemeData lightTheme() {
return ThemeData(
brightness: Brightness.light,
backgroundColor: AppColors.lightBackground,
cardColor: AppColors.lightSurface,
textTheme: TextTheme(
bodyLarge: TextStyle(color: AppColors.lightTextPrimary),
),
);
}
static ThemeData darkTheme() {
return ThemeData(
brightness: Brightness.dark,
backgroundColor: AppColors.darkBackground,
cardColor: AppColors.darkSurface,
textTheme: TextTheme(
bodyLarge: TextStyle(color: AppColors.darkTextPrimary),
),
);
}
}
4.4 使用Flutter Theme系统
结合Flutter的Theme系统,实现主题的全局管理:
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: AppStrings.appName,
theme: ThemeData(
// 使用自定义常量配置主题
primaryColor: AppColors.primary,
scaffoldBackgroundColor: AppColors.background,
cardColor: AppColors.surface,
// 配置Material组件主题
appBarTheme: AppBarTheme(
backgroundColor: AppColors.primary,
titleTextStyle: TextStyle(
color: AppColors.surface,
fontSize: AppFonts.sizeLarge,
fontWeight: FontWeight.bold,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: AppColors.surface,
padding: EdgeInsets.symmetric(
horizontal: AppSpacing.lg,
vertical: AppSpacing.sm,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.md),
),
),
),
),
home: const HomePage(),
);
}
}
4.5 在Widget中访问Theme
在Widget中通过Theme.of(context)访问主题配置:
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
color: theme.scaffoldBackgroundColor,
child: Text(
'Hello World',
style: TextStyle(
color: theme.textTheme.bodyLarge?.color,
fontSize: theme.textTheme.bodyLarge?.fontSize,
),
),
);
}
五、常量与不可变性的性能优化
5.1 使用const减少Widget重建
在Flutter中,使用const构造函数可以避免不必要的Widget重建:
// 好的做法:使用const
Widget build(BuildContext context) {
return const Scaffold(
appBar: AppBar(
title: const Text('标题'),
),
body: const Center(
child: const Text('内容'),
),
);
}
// 不好的做法:不使用const
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('标题'),
),
body: Center(
child: Text('内容'),
),
);
}
5.2 使用const集合优化内存
// 好的做法:使用const集合
const List<String> tags = ['Flutter', 'Dart', 'HarmonyOS'];
// 不好的做法:每次创建新集合
List<String> tags = ['Flutter', 'Dart', 'HarmonyOS'];
5.3 使用final缓存计算结果
class UserProfile {
final Person person;
late final String fullInfo;
UserProfile({required this.person}) {
// 只计算一次
fullInfo = _computeFullInfo();
}
String _computeFullInfo() {
return '姓名:${person.name},年龄:${person.age},职业:${person.occupation}';
}
}
5.4 使用const构造函数的条件
要使用const构造函数,必须满足以下条件:
- 构造函数必须用
const修饰 - 所有字段必须是
final类型 - 所有字段的值必须是编译时常量
// 可以使用const构造函数
class Point {
final double x;
final double y;
const Point({required this.x, required this.y});
}
// 不能使用const构造函数(因为DateTime.now()不是编译时常量)
class Timestamp {
final DateTime time;
// const Timestamp() : time = DateTime.now(); // 错误
Timestamp() : time = DateTime.now(); // 正确
}
六、在鸿蒙平台的特殊考虑
6.1 主题适配鸿蒙平台
在鸿蒙平台上,需要考虑系统主题的适配:
class AppColors {
// 鸿蒙平台特有颜色
static const Color harmonyAccent = Color(0xFF007DFF);
static const Color harmonyPrimary = Color(0xFF007DFF);
static const Color harmonySuccess = Color(0xFF00C853);
static const Color harmonyWarning = Color(0xFFFF9500);
static const Color harmonyError = Color(0xFFFF453A);
}
6.2 资源文件管理
在鸿蒙平台上,资源文件需要特殊处理:
class AppAssets {
static const String avatar = 'assets/images/avatar.png';
static const String logo = 'assets/images/logo.png';
static const String icon = 'assets/icons/icon.png';
}
6.3 国际化字符串
在鸿蒙平台上,需要支持国际化:
class AppStrings {
// 中文
static const String appName = 'Flutter学习助手';
static const String titlePersonalInfo = '个人信息卡片';
// 英文(需要配合国际化框架)
// static const String appName = 'Flutter Learning Assistant';
}
七、常见问题与解决方案
7.1 问题一:试图修改const变量
const int value = 10;
value = 20; // 错误:const变量不可修改
解决方案:使用var或final声明需要修改的变量。
7.2 问题二:const构造函数参数不是编译时常量
class MyWidget extends StatelessWidget {
final String text;
const MyWidget({required this.text}); // 如果text不是编译时常量,会报错
Widget build(BuildContext context) {
return Text(text);
}
}
// 错误用法
const MyWidget(text: 'Hello'); // 可以
const MyWidget(text: variable); // 错误:variable不是编译时常量
解决方案:如果参数不是编译时常量,不要使用const构造函数。
7.3 问题三:不可变集合包含可变元素
const List<MutablePerson> people = [
MutablePerson(name: '张三', age: 28),
];
people[0].age = 29; // 可以修改,因为MutablePerson是可变的
解决方案:确保集合中的元素也是不可变的。
7.4 问题四:过度使用const
// 不必要的const
Widget build(BuildContext context) {
const String dynamicText = '动态文本'; // 如果文本是动态生成的,不应该用const
return const Text(dynamicText);
}
解决方案:只在真正需要编译时常量时使用const。
八、完整示例代码
以下是本章知识点的完整示例代码,展示了常量与不可变性的实际应用:
import 'package:flutter/material.dart';
class AppColors {
static const Color primary = Color(0xFF2196F3);
static const Color primaryLight = Color(0xFF64B5F6);
static const Color primaryDark = Color(0xFF1976D2);
static const Color secondary = Color(0xFF4CAF50);
static const Color secondaryLight = Color(0xFF81C784);
static const Color secondaryDark = Color(0xFF388E3C);
static const Color accent = Color(0xFFFFC107);
static const Color accentLight = Color(0xFFFFD54F);
static const Color accentDark = Color(0xFFFFA000);
static const Color background = Color(0xFFF5F5F5);
static const Color surface = Color(0xFFFFFFFF);
static const Color error = Color(0xFFF44336);
static const Color textPrimary = Color(0xFF212121);
static const Color textSecondary = Color(0xFF757575);
static const Color textHint = Color(0xFF9E9E9E);
static const Color divider = Color(0xFFE0E0E0);
static const Color disabled = Color(0xFFBDBDBD);
static const Color shadow = Color(0x1F000000);
static const Color online = Color(0xFF4CAF50);
static const Color offline = Color(0xFF9E9E9E);
static const Color male = Color(0xFF2196F3);
static const Color female = Color(0xFFE91E63);
}
class AppFonts {
static const String family = 'Roboto';
static const double sizeExtraSmall = 10.0;
static const double sizeSmall = 12.0;
static const double sizeMedium = 14.0;
static const double sizeNormal = 16.0;
static const double sizeLarge = 18.0;
static const double sizeExtraLarge = 24.0;
static const double sizeTitle = 28.0;
static const double sizeHeading = 32.0;
}
class AppSpacing {
static const double xs = 4.0;
static const double sm = 8.0;
static const double md = 16.0;
static const double lg = 24.0;
static const double xl = 32.0;
static const double xxl = 48.0;
}
class AppRadius {
static const double sm = 4.0;
static const double md = 8.0;
static const double lg = 12.0;
static const double xl = 16.0;
static const double circular = 9999.0;
}
class AppDurations {
static const Duration instant = Duration(milliseconds: 100);
static const Duration fast = Duration(milliseconds: 200);
static const Duration normal = Duration(milliseconds: 300);
static const Duration slow = Duration(milliseconds: 500);
static const Duration long = Duration(seconds: 1);
}
class AppUrls {
static const String baseUrl = 'https://api.example.com';
static const String avatarUrl = 'https://api.example.com/avatar';
static const String userUrl = 'https://api.example.com/user';
}
class AppStrings {
static const String appName = 'Flutter学习助手';
static const String appVersion = '1.0.0';
static const String platform = 'HarmonyOS';
static const String titlePersonalInfo = '个人信息卡片';
static const String labelName = '姓名';
static const String labelAge = '年龄';
static const String labelOccupation = '职业';
static const String labelGender = '性别';
static const String labelEmail = '邮箱';
static const String labelPhone = '电话';
static const String labelLocation = '位置';
static const String labelBio = '个人简介';
static const String labelContact = '联系方式';
static const String labelSocialAccounts = '社交账号';
static const String hintName = '请输入姓名';
static const String hintAge = '请输入年龄';
static const String hintOccupation = '请输入职业';
static const String hintBio = '请输入个人简介';
static const String errorInvalidAge = '请输入有效的年龄';
static const String errorRequired = '此项不能为空';
static const String onlineText = '在线';
static const String offlineText = '离线';
static const String actionEdit = '编辑';
static const String actionSave = '保存';
static const String actionCancel = '取消';
}
总结
本章我们深入探讨了Dart中的常量声明机制和不可变性原则,主要内容包括:
- 常量声明方式:
const编译时常量和final运行时常量的区别与使用场景 - 不可变性原则:不可变对象的好处、实现方式、不可变集合
- 主题色常量配置:创建常量管理文件、在应用中使用常量
- 主题配置最佳实践:单一职责原则、语义化命名、明暗主题支持、Flutter Theme系统
- 性能优化:使用
const减少Widget重建、使用const集合优化内存、使用final缓存计算结果 - 鸿蒙平台特殊考虑:主题适配、资源文件管理、国际化支持
通过本章的学习,你应该能够熟练地在鸿蒙平台的Flutter应用中配置和使用常量,遵循不可变性原则,构建高质量、高性能的应用。
文档版本:v1.0
创建日期:2026年7月18日
更多推荐



所有评论(0)