增强变焦功能

This commit is contained in:
2026-06-12 18:35:18 +08:00
parent 25ac9c4c35
commit d39d85cd99
4 changed files with 513 additions and 41 deletions

View File

@@ -56,7 +56,7 @@ class RecordingHudWidget extends StatelessWidget {
static double get _recordButtonBottom => 63.r;
static double get _overlayInfoLeft => 13.r;
static double get _overlayInfoBottom => 10.r;
static const List<double> _zoomPresets = [1.0, 2.0, 3.0];
static const List<double> _zoomPresets = [0.6, 1.0];
@override
Widget build(BuildContext context) {
@@ -146,6 +146,7 @@ class RecordingHudWidget extends StatelessWidget {
right: 16.r,
bottom: _recordButtonBottom + _recordButtonSize + 14.h,
child: _ZoomPresetControl(
isRecording: isRecording,
zoomRatio: zoomRatio,
minZoomRatio: minZoomRatio,
maxZoomRatio: maxZoomRatio,
@@ -194,6 +195,7 @@ class RecordingHudWidget extends StatelessWidget {
class _ZoomPresetControl extends StatelessWidget {
const _ZoomPresetControl({
required this.isRecording,
required this.zoomRatio,
required this.minZoomRatio,
required this.maxZoomRatio,
@@ -201,6 +203,7 @@ class _ZoomPresetControl extends StatelessWidget {
required this.onSelected,
});
final bool isRecording;
final double zoomRatio;
final double minZoomRatio;
final double maxZoomRatio;
@@ -210,7 +213,7 @@ class _ZoomPresetControl extends StatelessWidget {
@override
Widget build(BuildContext context) {
final availablePresets = presets
.where((preset) => preset >= minZoomRatio && preset <= maxZoomRatio)
.where(_isPresetAvailable)
.toList(growable: false);
if (availablePresets.isEmpty) {
@@ -230,8 +233,10 @@ class _ZoomPresetControl extends StatelessWidget {
children: [
for (final preset in availablePresets)
_ZoomPresetButton(
ratio: preset,
selected: (zoomRatio - preset).abs() < 0.05,
displayRatio: preset,
requestRatio: _requestRatioFor(preset),
selected: _isPresetSelected(preset),
enabled: !_wouldSwitchPhysicalCamera(preset),
onSelected: onSelected,
),
],
@@ -239,17 +244,51 @@ class _ZoomPresetControl extends StatelessWidget {
),
);
}
bool _isPresetAvailable(double preset) {
if (preset < 1.0) {
return minZoomRatio <= preset && maxZoomRatio >= preset;
}
return preset >= minZoomRatio && preset <= maxZoomRatio;
}
bool _isPresetSelected(double preset) {
if (preset < 1.0) {
return zoomRatio < 1.0;
}
return (zoomRatio - preset).abs() < 0.05;
}
double _requestRatioFor(double preset) {
if (preset < 1.0) {
return minZoomRatio <= 0.5 ? 0.5 : preset;
}
return preset;
}
bool _wouldSwitchPhysicalCamera(double preset) {
if (!isRecording) {
return false;
}
final currentIsUltraWide = zoomRatio < 1.0;
final targetIsUltraWide = preset < 1.0;
return currentIsUltraWide != targetIsUltraWide;
}
}
class _ZoomPresetButton extends StatelessWidget {
const _ZoomPresetButton({
required this.ratio,
required this.displayRatio,
required this.requestRatio,
required this.selected,
required this.enabled,
required this.onSelected,
});
final double ratio;
final double displayRatio;
final double requestRatio;
final bool selected;
final bool enabled;
final ValueChanged<double> onSelected;
@override
@@ -257,7 +296,7 @@ class _ZoomPresetButton extends StatelessWidget {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 1.r),
child: TextButton(
onPressed: selected ? null : () => onSelected(ratio),
onPressed: selected || !enabled ? null : () => onSelected(requestRatio),
style: TextButton.styleFrom(
minimumSize: Size(38.r, 32.r),
padding: EdgeInsets.zero,
@@ -271,7 +310,7 @@ class _ZoomPresetButton extends StatelessWidget {
),
),
child: Text(
'${ratio.toStringAsFixed(0)}x',
'${_formatZoomRatio(displayRatio)}x',
style: TextStyle(
fontSize: 13.sp,
fontWeight: FontWeight.w700,
@@ -281,4 +320,11 @@ class _ZoomPresetButton extends StatelessWidget {
),
);
}
String _formatZoomRatio(double ratio) {
if (ratio == ratio.roundToDouble()) {
return ratio.toStringAsFixed(0);
}
return ratio.toStringAsFixed(1);
}
}