import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import '../../hj_model/home/plate_model.dart'; import '../../hj_utils/screen.dart'; import 'home_drawer_logic.dart'; import 'home_main_logic.dart'; class HSHomeDrawer extends StatelessWidget { final HomeMainLogic homeLogic; const HSHomeDrawer({super.key, required this.homeLogic}); @override Widget build(BuildContext context) { return GetBuilder( init: HomeDrawerLogic(homeLogic), builder: (logic) { return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => logic.goBack(), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: SizedBox( width: screen.screenWidth, height: screen.screenHeight, child: Align( alignment: Alignment.topRight, child: Container( width: 212, height: screen.screenHeight, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 18), clipBehavior: Clip.antiAlias, decoration: const BoxDecoration(color: Colors.black), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 32.sizeBoxH, _headerRow(logic), 4.sizeBoxH, Text( '长按拖动排序', style: TextStyle( color: Colors.white.withValues(alpha: 0.45), fontSize: 12, ), ), 18.sizeBoxH, Expanded(child: _buildGridContent(logic)), ], ), ), ), ), ), ); }, ); } Widget _headerRow(HomeDrawerLogic logic) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '导航列表', style: TextStyle( color: Colors.white.withValues(alpha: 0.9), fontSize: 16, fontWeight: FontWeight.w500, ), ), const Spacer(), InkWell(enableFeedback: false, onTap: logic.resetToDefault, child: Container( padding: const EdgeInsets.fromLTRB(6, 2, 0, 6), child: Text( '恢复默认', style: TextStyle( color: Colors.white.withValues(alpha: 0.45), fontSize: 12, ), ), ), ), ], ); } //抽屉列表:Stack + AnimatedPositioned,排序变化时 item 平滑滑到新位置 Widget _buildGridContent(HomeDrawerLogic logic) { const cross = 2; // 列数 const spacing = 12.0; // 行列间距 const ratio = 84 / 40; // item 宽高比 return LayoutBuilder( builder: (context, constraints) { final itemW = (constraints.maxWidth - spacing * (cross - 1)) / cross; final itemH = itemW / ratio; final rows = (logic.dataArr.length / cross).ceil(); final totalH = rows * itemH + (rows > 0 ? rows - 1 : 0) * spacing; return SingleChildScrollView( child: SizedBox( height: totalH, child: Stack( children: [ for (int i = 0; i < logic.dataArr.length; i++) _positionedItem(logic, i, itemW, itemH, spacing, cross), ], ), ), ); }, ); } //单个 item 的定位 + 交换补间动画(key 用 id 保证身份稳定,位置变化才会补间) Widget _positionedItem( HomeDrawerLogic logic, int index, double w, double h, double spacing, int cross, ) { final tabModel = logic.dataArr[index]; final isSelected = logic.curTagData?.id == tabModel.id; final row = index ~/ cross; final col = index % cross; return AnimatedPositioned( key: ValueKey(tabModel.id), duration: const Duration(milliseconds: 250), curve: Curves.easeInOut, left: col * (w + spacing), top: row * (h + spacing), width: w, height: h, child: _buildDraggableItem(logic, tabModel, isSelected, w, h), ); } Widget _buildDraggableItem(HomeDrawerLogic logic, ModuleData tabModel, bool isSelected, double w, double h) { return DragTarget( onAcceptWithDetails: (details) => logic.reorderItem(details.data, tabModel), builder: (context, candidateData, rejectedData) { final itemBody = Container( alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), color: isSelected ? const Color(0xfff68804) : const Color(0x1AFFFFFF), ), child: GestureDetector( onTap: () => logic.goBack(selectedModel: tabModel), child: Text( tabModel.moduleName ?? '', style: const TextStyle(fontSize: 14, color: Colors.white), ), ), ); return LongPressDraggable( data: tabModel, hapticFeedbackOnStart: false, // 关掉默认轻震,用下面更明显的震动 onDragStarted: () => HapticFeedback.mediumImpact(), // 长按触发时震一下 feedback: Material( color: Colors.transparent, child: Container( width: w, height: h, alignment: Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), color: const Color(0xffF68804), // 主题色(拖起态不透明) ), child: Text( tabModel.moduleName ?? '', style: const TextStyle(fontSize: 12, color: Colors.white), ), ), ), childWhenDragging: Opacity(opacity: 0.4, child: itemBody), // 占位:半透明 child: itemBody, ); }, ); } }