part of 'operate_bar.dart'; class _ContrastToneBar extends StatefulWidget { @override State createState() => _ContrastToneBarState(); } class _ContrastToneBarState extends State<_ContrastToneBar> { late final measureController = Get.find(); VidPlayerController playerController = Get.find() as VidPlayerController; ///屏幕缩放比例 double get devicePixelRatio => kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio; double curValue = 0; @override void initState() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { if (mounted) { playerController.eventHandler.addListener(onControllerEvent); measureController.imageLoaded.addListener(updatePlayerController); } }); super.initState(); } /// 更新 controller void updatePlayerController(a, b) { playerController.eventHandler.removeListener(onControllerEvent); playerController = Get.find() as VidPlayerController; playerController.eventHandler.addListener(onControllerEvent); } @override Widget build(BuildContext context) { return _ToneBar( max: 100, min: -100, value: curValue, icon: Icon( Icons.contrast, color: Colors.white, size: 24 / devicePixelRatio, ), onChange: (v) { playerController.setContrast(v.toInt()); }, ); } @override void dispose() { playerController.eventHandler.removeListener(onControllerEvent); measureController.imageLoaded.removeListener(updatePlayerController); super.dispose(); } void onControllerEvent(Object sender, VidPlayerEvent e) { if (e is VidPlayResetToneEvent) { onResetTone(); } } void onResetTone() { setState(() { curValue = 0; }); } } class _BrightnessToneBar extends StatefulWidget { @override State createState() => _BrightnessToneBarState(); } class _BrightnessToneBarState extends State<_BrightnessToneBar> { late final measureController = Get.find(); VidPlayerController playerController = Get.find() as VidPlayerController; ///屏幕缩放比例 double get devicePixelRatio => kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio; double curValue = 0; @override void initState() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { if (mounted) { playerController.eventHandler.addListener(onControllerEvent); measureController.imageLoaded.addListener(updatePlayerController); } }); super.initState(); } /// 更新 controller void updatePlayerController(a, b) { playerController.eventHandler.removeListener(onControllerEvent); playerController = Get.find() as VidPlayerController; playerController.eventHandler.addListener(onControllerEvent); } @override Widget build(BuildContext context) { return _ToneBar( max: 100, min: -100, value: curValue, icon: Icon( Icons.wb_sunny_sharp, color: Colors.white, size: 24 / devicePixelRatio, ), onChange: (v) { playerController.setBrightness(v.toInt()); }, ); } @override void dispose() { playerController.eventHandler.removeListener(onControllerEvent); measureController.imageLoaded.removeListener(updatePlayerController); super.dispose(); } void onControllerEvent(Object sender, VidPlayerEvent e) { if (e is VidPlayResetToneEvent) { onResetTone(); } } void onResetTone() { setState(() { curValue = 0; }); } } class _ToneBar extends StatefulWidget { const _ToneBar({ Key? key, required this.icon, required this.min, required this.max, required this.value, this.onChange, }) : super(key: key); final Widget icon; final ValueChanged? onChange; final double min; final double max; final double value; final Color themeColor = Colors.white; @override State createState() => _ToneBarState(); } class _ToneBarState extends State<_ToneBar> { double get _kIconSize => 20.0 / devicePixelRatio; double get splashRadius => _kIconSize / 2 + 3; double get devicePixelRatio => kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio; late double _value; @override void initState() { syncProps(); super.initState(); } @override void didUpdateWidget(covariant _ToneBar oldWidget) { syncProps(); super.didUpdateWidget(oldWidget); } void syncProps() { _value = widget.value; } @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ widget.icon, const SizedBox(width: 8), buildReduceIcon(), buildSlider(context), buildIncreaseIcon(), const SizedBox(width: 8), SizedBox( width: 30 / devicePixelRatio, child: Text( '${_value.toInt()}', style: TextStyle(color: widget.themeColor), )), ], ); } Widget buildReduceIcon() { return IconButton( color: widget.themeColor, constraints: BoxConstraints( minHeight: _kIconSize, minWidth: _kIconSize, ), splashRadius: splashRadius, padding: EdgeInsets.zero, onPressed: () { updateValue(_value - 1); }, icon: Icon(Icons.remove_circle_outline, size: _kIconSize), ); } Widget buildIncreaseIcon() { return IconButton( color: widget.themeColor, constraints: BoxConstraints( minHeight: _kIconSize, minWidth: _kIconSize, ), splashRadius: splashRadius, padding: EdgeInsets.zero, onPressed: () { updateValue(_value + 1); }, icon: Icon(Icons.add_circle_outline, size: _kIconSize), ); } Widget buildSlider(BuildContext context) { final trackColor = Theme.of(context).primaryColor; return Expanded( child: SliderTheme( data: SliderThemeData( trackHeight: 4, activeTrackColor: trackColor, inactiveTrackColor: trackColor, thumbColor: Colors.grey[300], thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 6, elevation: 3.0, ), overlayShape: SliderComponentShape.noOverlay, trackShape: _FullWidthRectangularSliderTrackShape( padding: const EdgeInsets.symmetric(horizontal: 4), devicePixelRatio: devicePixelRatio, ), ), child: Slider( max: widget.max, min: widget.min, value: _value, label: _value.toInt().toString(), divisions: (widget.max - widget.min).toInt(), onChanged: (v) { updateValue(v); }, ), ), ); } void updateValue(double value) { if (value < widget.min || value > widget.max) { return; } setState(() { _value = value; }); widget.onChange?.call(value); } } class _FullWidthRectangularSliderTrackShape extends RectangularSliderTrackShape { const _FullWidthRectangularSliderTrackShape({ this.padding, this.devicePixelRatio = 1, }); final EdgeInsets? padding; final double devicePixelRatio; @override Rect getPreferredRect({ required RenderBox parentBox, Offset offset = Offset.zero, required SliderThemeData sliderTheme, bool isEnabled = false, bool isDiscrete = false, }) { double trackHeight = sliderTheme.trackHeight ?? 2; double trackLeft = offset.dx; double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2; // 让轨道宽度等于 Slider 宽度 double trackWidth = parentBox.size.width; if (padding != null) { trackHeight -= padding!.bottom; trackHeight -= padding!.top; trackWidth -= padding!.right; trackWidth -= padding!.left; trackTop += padding!.top; trackLeft += padding!.left; } return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); } } class _ResetToneButton extends StatelessWidget { @override Widget build(BuildContext context) { return ElevatedButton( onPressed: () { final playerController = Get.find() as VidPlayerController; playerController.resetTone(); }, child: Text( i18nBook.measure.resetTone4Btn.t, style: const TextStyle( color: Colors.white, fontSize: 16, ), ), ); } }