Files
flutterApp/lib/features/remote_control/presentation/widgets/middle_expandslider.dart
2026-01-18 20:21:14 +08:00

133 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MiddleExpandSlider extends StatefulWidget {
final VoidCallback onTop; // 对应 Compose 的 onTop (例如:升)
final VoidCallback onMiddle; // 对应 Compose 的 onMiddle (例如:停止/复位)
final VoidCallback onBottom; // 对应 Compose 的 onBottom (例如:降)
final IconData iconTop;
final IconData iconMiddle;
final IconData iconBottom;
const MiddleExpandSlider({
super.key,
required this.onTop,
required this.onMiddle,
required this.onBottom,
required this.iconTop,
required this.iconMiddle,
required this.iconBottom,
});
@override
State<MiddleExpandSlider> createState() => _MiddleExpandSliderState();
}
class _MiddleExpandSliderState extends State<MiddleExpandSlider> {
// 0: Top, 1: Middle, 2: Bottom
int _currentIndex = 1;
// 处理滑动更新逻辑
void _handleDragUpdate(DragUpdateDetails details, double maxHeight) {
// 将 120 的高度分为三等份
double localY = details.localPosition.dy;
int newIndex;
if (localY < maxHeight / 3) {
newIndex = 0;
} else if (localY > (maxHeight / 3) * 2) {
newIndex = 2;
} else {
newIndex = 1;
}
if (newIndex != _currentIndex) {
setState(() => _currentIndex = newIndex);
// 触发对应的指令回调
if (_currentIndex == 0) widget.onTop();
if (_currentIndex == 1) widget.onMiddle();
if (_currentIndex == 2) widget.onBottom();
// 触感反馈:对应 Android 的 VibrateOnce(current, 20)
HapticFeedback.lightImpact();
}
}
// 对应 Compose 的松手回弹逻辑
void _handleDragEnd() {
if (_currentIndex != 1) {
setState(() => _currentIndex = 1);
widget.onMiddle(); // 回到中间,停止动作
HapticFeedback.selectionClick();
}
}
@override
Widget build(BuildContext context) {
const double sliderHeight = 120.0;
const double sliderWidth = 45.0;
return GestureDetector(
onVerticalDragUpdate: (details) =>
_handleDragUpdate(details, sliderHeight),
onVerticalDragEnd: (_) => _handleDragEnd(),
child: Container(
width: sliderWidth,
height: sliderHeight,
decoration: BoxDecoration(
color: Colors.grey.withOpacity(
0.2,
), // 对应 Color.Gray.copy(alpha = 0.4f)
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withOpacity(0.2), width: 0.5),
),
child: Stack(
alignment: Alignment.center,
children: [
// 1. 背景图标层:提示用户上下功能
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(widget.iconTop, color: Colors.white12, size: 20),
Icon(widget.iconMiddle, color: Colors.white12, size: 20),
Icon(widget.iconBottom, color: Colors.white12, size: 20),
],
),
// 2. 活动滑块:对应 Compose 中的蓝色选中状态
AnimatedPositioned(
duration: const Duration(milliseconds: 150),
curve: Curves.easeOutBack, // 增加一点点弹簧感
top: _currentIndex == 0 ? 5 : (_currentIndex == 1 ? 40 : 75),
child: Container(
width: 38,
height: 40,
decoration: BoxDecoration(
color: const Color(0xCC0078D4), // 对应 Compose 里的蓝色
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: const Color(0xCC0078D4).withOpacity(0.4),
blurRadius: 8,
spreadRadius: 1,
),
],
),
child: Icon(
_currentIndex == 0
? widget.iconTop
: (_currentIndex == 1
? widget.iconMiddle
: widget.iconBottom),
color: Colors.white,
size: 22,
),
),
),
],
),
),
);
}
}