在垃圾分类应用开发中,处罚标准页面是一个需要特别谨慎处理的功能模块。这个页面既要起到警示作用,又要避免给用户造成过度压力。通过Flutter for OpenHarmony实现这个功能时,我们需要考虑以下几个关键点:
这个页面最终实现了四大主体(个人、单位、收运单位、处置单位)的处罚标准展示,包含金额区间、违规行为描述等核心信息,并通过合理的UI设计达到了警示与友好的平衡。
我们选择SingleChildScrollView作为根布局,而不是ListView,原因如下:
这种选择符合"简单有效"的原则,避免了不必要的复杂性。对于内容较长的页面,SingleChildScrollView能提供流畅的滚动体验,同时避免了ListView的一些潜在性能问题。
页面采用典型的Material Design布局结构:
code复制Scaffold
└── AppBar
└── SingleChildScrollView
└── Column
├── 警示区Container
├── 标题Text
├── 处罚卡片列表(4个Card)
├── 标题Text
└── 温馨提示Card
这种结构清晰明了,每个区块都有明确的职责,便于维护和扩展。
我们定义了两种数据表示方式:
适用于快速原型开发:
dart复制final penalties = [
{'type': '个人', 'amount': '50-200元', 'desc': '未按规定分类投放生活垃圾'},
// 其他主体类型...
];
推荐在实际项目中使用:
dart复制class PenaltyItem {
final String type; // 主体类型
final String amount; // 处罚金额区间
final String description; // 违规行为描述
final String? legalBasis; // 法律依据
PenaltyItem({
required this.type,
required this.amount,
required this.description,
this.legalBasis,
});
}
Model类的优势:
顶部警示区采用了醒目的设计,但避免了过度刺激:
dart复制Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.amber.withOpacity(0.1), // 半透明琥珀色背景
borderRadius: BorderRadius.circular(12.r),
border: Border.all(color: Colors.amber.withOpacity(0.3)),
),
child: Row(
children: [
Icon(Icons.warning, color: Colors.amber, size: 32.sp),
SizedBox(width: 12.w),
Expanded(
child: Text(
'垃圾分类已纳入法律法规,违规投放将面临处罚',
style: TextStyle(fontSize: 14.sp),
),
),
],
),
)
设计要点:
每个处罚标准使用Card组件展示:
dart复制Card(
margin: EdgeInsets.only(bottom: 12.h),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Row(
children: [
// 主体类型标签
Container(
width: 60.w,
height: 60.w,
decoration: BoxDecoration(
color: AppTheme.hazardousColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
),
child: Center(
child: Text(
penalty['type']!,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: AppTheme.hazardousColor,
),
),
),
),
SizedBox(width: 16.w),
// 处罚详情
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'罚款 ${penalty['amount']}',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: AppTheme.hazardousColor,
),
),
SizedBox(height: 4.h),
Text(
penalty['desc']!,
style: TextStyle(fontSize: 13.sp, color: Colors.grey),
),
],
),
),
],
),
),
)
设计考虑:
为了缓和页面的严肃氛围,我们添加了温馨提示区域:
dart复制Card(
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTipItem('首次违规通常以教育为主'),
_buildTipItem('多次违规将依法处罚'),
_buildTipItem('情节严重的将纳入信用记录'),
_buildTipItem('建议主动学习分类知识'),
],
),
),
)
提示项组件实现:
dart复制Widget _buildTipItem(String text) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
children: [
Icon(Icons.check_circle, color: AppTheme.primaryColor, size: 18.sp),
SizedBox(width: 8.w),
Text(text, style: TextStyle(fontSize: 14.sp)),
],
),
);
}
设计意图:
增强页面权威性的可折叠区域:
dart复制ExpansionTile(
title: Text('法律依据', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
children: [
Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildLegalItem('《上海市生活垃圾管理条例》', '2019年7月1日起施行'),
_buildLegalItem('《北京市生活垃圾管理条例》', '2020年5月1日起施行'),
_buildLegalItem('《深圳市生活垃圾分类管理条例》', '2020年9月1日起施行'),
],
),
),
],
)
法律条目组件:
dart复制Widget _buildLegalItem(String title, String date) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: TextStyle(fontSize: 14.sp)),
Text(date, style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
],
),
);
}
价值体现:
尽可能使用const构造函数减少Widget重建开销:
dart复制const Icon(Icons.warning, color: Colors.amber, size: 32)
const Text('处罚标准')
将常用UI元素提取为独立组件:
dart复制class WarningBanner extends StatelessWidget {
final String message;
const WarningBanner({super.key, required this.message});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.amber.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
border: Border.all(color: Colors.amber.withOpacity(0.3)),
),
child: Row(
children: [
const Icon(Icons.warning, color: Colors.amber, size: 32),
SizedBox(width: 12.w),
Expanded(child: Text(message, style: TextStyle(fontSize: 14.sp))),
],
),
);
}
}
好处:
对于长列表,使用ListView.builder而非直接构建所有子项:
dart复制ListView.builder(
itemCount: penalties.length,
itemBuilder: (context, index) => _buildPenaltyCard(penalties[index]),
)
虽然本例中只有4个卡片,但养成这种习惯有助于应对未来可能的内容扩展。
点击卡片展示详细信息:
dart复制void _showPenaltyDetail(BuildContext context, Map<String, dynamic> penalty) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => DraggableScrollableSheet(
initialChildSize: 0.7,
builder: (context, scrollController) => SingleChildScrollView(
controller: scrollController,
child: Column(
children: [
// 详情内容
],
),
),
),
);
}
设计特点:
快速定位特定处罚标准:
dart复制class PenaltyStandardsPage extends StatefulWidget {
const PenaltyStandardsPage({super.key});
@override
State<PenaltyStandardsPage> createState() => _PenaltyStandardsPageState();
}
class _PenaltyStandardsPageState extends State<PenaltyStandardsPage> {
String _searchQuery = '';
List<Map<String, dynamic>> _getFilteredPenalties() {
if (_searchQuery.isEmpty) return penalties;
return penalties.where((p) =>
p['target'].contains(_searchQuery) ||
p['violation'].contains(_searchQuery)
).toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('处罚标准'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () => _showSearchDialog(),
),
],
),
body: ListView.builder(
itemCount: _getFilteredPenalties().length,
itemBuilder: (context, index) {
return _buildPenaltyCard(_getFilteredPenalties()[index]);
},
),
);
}
}
实现要点:
帮助用户预估违规成本:
dart复制class PenaltyCalculatorPage extends StatefulWidget {
const PenaltyCalculatorPage({super.key});
@override
State<PenaltyCalculatorPage> createState() => _PenaltyCalculatorPageState();
}
class _PenaltyCalculatorPageState extends State<PenaltyCalculatorPage> {
String _selectedTarget = '个人';
int _violationCount = 1;
int _calculatePenalty() {
final base = _selectedTarget == '个人' ? 200 : 50000;
return base * _violationCount;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('处罚计算器')),
body: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
// 主体类型选择
SegmentedButton<String>(
segments: const [
ButtonSegment(value: '个人', label: Text('个人')),
ButtonSegment(value: '单位', label: Text('单位')),
],
selected: {_selectedTarget},
onSelectionChanged: (Set<String> newSelection) {
setState(() => _selectedTarget = newSelection.first);
},
),
// 违规次数选择
Row(
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: _violationCount > 1
? () => setState(() => _violationCount--)
: null,
),
Text(_violationCount.toString()),
IconButton(
icon: const Icon(Icons.add),
onPressed: () => setState(() => _violationCount++),
),
],
),
// 计算结果展示
Text('¥${_calculatePenalty()}'),
],
),
),
);
}
}
教育意义:
处罚标准页面的设计需要在多个维度找到平衡点:
严肃性与友好性
完整性与简洁性
规范性与灵活性
本页面精心选择了颜色方案:
这种配色方案既达到了视觉区分的效果,又符合用户对颜色的心理预期。
信息架构遵循"金字塔原则":
这种结构确保用户能快速获取关键信息,同时可以根据需要深入了解细节。
不同屏幕尺寸测试
文字缩放测试
暗黑模式测试
信息获取效率
情感反应评估
操作便利性
本地化支持
数据动态化
智能推荐
社区互动
增强现实
模块化设计
性能优先
用户体验考量
问题:警示效果不足
问题:页面过于严肃
问题:数据维护困难
问题:布局适配问题
问题:交互反馈不足
在实际开发中,我们发现将处罚标准与具体的垃圾分类指南关联展示,能够取得更好的教育效果。用户不仅知道"不能做什么",还清楚"应该怎么做",这才是我们设计这个功能的最终目的。