Files
xianyan/lib/core/layout/split_divider.dart
Developer ca68fe29c7 chore: 批量整理优化项目代码与配置
- 新增模型目录占位文件与翻译类型拆分
- 调整路由配置与桌面端窗口初始化
- 移除多处冗余图表配置项
- 重构右侧面板注册表与三栏布局组件
- 添加智能AppBar、拖拽书签等新功能组件
- 优化安卓编译配置与多平台插件注册
- 新增翻译覆盖率测试与共享组件
- 格式化代码与修复静态分析警告
2026-05-29 10:08:02 +08:00

119 lines
3.5 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// ============================================================
/// 闲言APP — 可拖拽分割线
/// 创建时间: 2026-05-29
/// 更新时间: 2026-05-29
/// 作用: 宽屏分屏的分割线组件支持拖拽调整比例、hover高亮、触觉反馈
/// 上次更新: 桌面端跳过HapticFeedback触觉反馈(桌面端无振动马达)
/// ============================================================
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import '../theme/app_theme.dart';
import '../utils/platform/platform_utils.dart' as pu;
class SplitDivider extends StatefulWidget {
const SplitDivider({
required this.onPositionChanged,
this.currentPosition = 0.4,
this.minPosition = 0.2,
this.maxPosition = 0.7,
this.isVertical = true,
super.key,
});
final ValueChanged<double> onPositionChanged;
final double currentPosition;
final double minPosition;
final double maxPosition;
final bool isVertical;
@override
State<SplitDivider> createState() => _SplitDividerState();
}
class _SplitDividerState extends State<SplitDivider> {
bool _isHovering = false;
bool _isDragging = false;
@override
Widget build(BuildContext context) {
final ext = AppTheme.ext(context);
final dividerColor = ext.textHint.withValues(alpha: 0.15);
final handleColor = _isDragging
? ext.accent.withValues(alpha: 0.8)
: _isHovering
? ext.accent.withValues(alpha: 0.5)
: ext.textHint.withValues(alpha: 0.3);
return MouseRegion(
onEnter: (_) => setState(() => _isHovering = true),
onExit: (_) => setState(() => _isHovering = false),
cursor: SystemMouseCursors.resizeColumn,
child: GestureDetector(
onHorizontalDragStart: _onDragStart,
onHorizontalDragUpdate: _onDragUpdate,
onHorizontalDragEnd: _onDragEnd,
onDoubleTap: () {
if (!pu.isDesktop) {
HapticFeedback.mediumImpact();
}
widget.onPositionChanged(0.4);
},
behavior: HitTestBehavior.translucent,
child: Container(
width: 24,
alignment: Alignment.center,
child: Container(
width: 1,
color: dividerColor,
child: Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 150),
curve: Curves.easeOut,
width: _isDragging
? 6
: _isHovering
? 4
: 4,
height: 32,
decoration: BoxDecoration(
color: handleColor,
borderRadius: BorderRadius.circular(2),
),
),
),
),
),
),
);
}
void _onDragStart(DragStartDetails details) {
setState(() => _isDragging = true);
if (!pu.isDesktop) {
HapticFeedback.selectionClick();
}
}
void _onDragUpdate(DragUpdateDetails details) {
final box = context.findRenderObject() as RenderBox;
final parent = box.parent as RenderBox;
final totalWidth = parent.size.width;
if (totalWidth <= 0) return;
final localX =
details.globalPosition.dx - parent.localToGlobal(Offset.zero).dx;
final newPosition = (localX / totalWidth).clamp(
widget.minPosition,
widget.maxPosition,
);
widget.onPositionChanged(newPosition);
}
void _onDragEnd(DragEndDetails details) {
setState(() => _isDragging = false);
}
}