feat: K线图添加技术指标切换(MA/EMA/BOLL/VOL/MACD),修复设置面板显示问题

This commit is contained in:
2026-04-07 17:07:25 +08:00
parent bc8462cc52
commit 01ded943bc
85 changed files with 44737 additions and 44471 deletions

View File

@@ -60,7 +60,10 @@ class ChartPage extends StatelessWidget {
// 2. 时间周期选择
_buildIntervalTabs(context, provider),
// 3. K线图区域
// 3. 技术指标切换
_buildIndicatorTabs(context, provider),
// 4. K线图区域
Expanded(
child: InteractiveChart(
candles: candles,
@@ -99,7 +102,7 @@ class ChartPage extends StatelessWidget {
),
),
// 4. 底部操作栏
// 5. 底部操作栏
_buildBottomActions(context, provider),
],
);
@@ -265,6 +268,101 @@ class ChartPage extends StatelessWidget {
);
}
/// 技术指标切换
Widget _buildIndicatorTabs(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors;
final indicators = [
{'key': 'MA', 'label': 'MA', 'value': provider.indicators.showMA},
{'key': 'EMA', 'label': 'EMA', 'value': provider.indicators.showEMA},
{'key': 'BOLL', 'label': 'BOLL', 'value': provider.indicators.showBOLL},
{'key': 'VOL', 'label': 'VOL', 'value': provider.indicators.showVOL},
{'key': 'MACD', 'label': 'MACD', 'value': provider.indicators.showMACD},
];
return Container(
height: 36,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.sm),
decoration: BoxDecoration(
color: colorScheme.surfaceContainer,
border: Border(
bottom: BorderSide(
color: colorScheme.outlineVariant.withValues(alpha: 0.2),
),
),
),
child: Row(
children: indicators.map((item) {
final isSelected = item['value'] as bool;
final key = item['key'] as String;
final label = item['label'] as String;
return Padding(
padding: const EdgeInsets.only(right: AppSpacing.xs),
child: InkWell(
onTap: () {
switch (key) {
case 'MA':
provider.updateIndicators(
provider.indicators.copyWith(showMA: !isSelected),
);
break;
case 'EMA':
provider.updateIndicators(
provider.indicators.copyWith(showEMA: !isSelected),
);
break;
case 'BOLL':
provider.updateIndicators(
provider.indicators.copyWith(showBOLL: !isSelected),
);
break;
case 'VOL':
provider.updateIndicators(
provider.indicators.copyWith(showVOL: !isSelected),
);
break;
case 'MACD':
provider.updateIndicators(
provider.indicators.copyWith(showMACD: !isSelected),
);
break;
}
},
borderRadius: BorderRadius.circular(AppRadius.sm),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.xs,
),
decoration: BoxDecoration(
color: isSelected
? colorScheme.primary.withValues(alpha: 0.1)
: Colors.transparent,
borderRadius: BorderRadius.circular(AppRadius.sm),
border: Border.all(
color: isSelected
? colorScheme.primary
: colorScheme.outlineVariant.withValues(alpha: 0.3),
width: 1,
),
),
child: Text(
label,
style: AppTextStyles.labelSmall(context).copyWith(
color: isSelected
? colorScheme.primary
: colorScheme.onSurfaceVariant,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
),
),
),
),
);
}).toList(),
),
);
}
/// 底部操作栏
Widget _buildBottomActions(BuildContext context, ChartProvider provider) {
final colorScheme = context.colors;
@@ -395,10 +493,12 @@ class ChartPage extends StatelessWidget {
}
void _showSettingsSheet(BuildContext context) {
final provider = context.read<ChartProvider>();
showModalBottomSheet(
context: context,
builder: (ctx) => Consumer<ChartProvider>(
builder: (ctx, provider, _) {
builder: (ctx) => StatefulBuilder(
builder: (ctx, setState) {
return Container(
padding: const EdgeInsets.all(AppSpacing.lg),
child: Column(
@@ -414,24 +514,66 @@ class ChartPage extends StatelessWidget {
const SizedBox(height: AppSpacing.lg),
_buildIndicatorSwitch(
context: ctx,
context: context,
label: 'MA 移动平均线 (7/14/30)',
value: provider.indicators.showMA,
onChanged: (v) => provider.updateIndicators(
provider.indicators.copyWith(showMA: v),
),
onChanged: (v) {
provider.updateIndicators(
provider.indicators.copyWith(showMA: v),
);
setState(() {});
},
),
_buildIndicatorSwitch(
context: ctx,
label: 'VOL 成交量',
value: provider.indicators.showVOL,
onChanged: (v) => provider.updateIndicators(
provider.indicators.copyWith(showVOL: v),
),
context: context,
label: 'EMA 指数移动平均',
value: provider.indicators.showEMA,
onChanged: (v) {
provider.updateIndicators(
provider.indicators.copyWith(showEMA: v),
);
setState(() {});
},
),
const SizedBox(height: AppSpacing.lg),
_buildIndicatorSwitch(
context: context,
label: 'BOLL 布林带',
value: provider.indicators.showBOLL,
onChanged: (v) {
provider.updateIndicators(
provider.indicators.copyWith(showBOLL: v),
);
setState(() {});
},
),
_buildIndicatorSwitch(
context: context,
label: 'VOL 成交量',
value: provider.indicators.showVOL,
onChanged: (v) {
provider.updateIndicators(
provider.indicators.copyWith(showVOL: v),
);
setState(() {});
},
),
_buildIndicatorSwitch(
context: context,
label: 'MACD',
value: provider.indicators.showMACD,
onChanged: (v) {
provider.updateIndicators(
provider.indicators.copyWith(showMACD: v),
);
setState(() {});
},
),
const SizedBox(height: AppSpacing.xl),
],
),
);