import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/ble_test_controller.dart'; class BleTestView extends GetView { const BleTestView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('BLE测试'), actions: [ Obx(() => IconButton( icon: const Icon(Icons.refresh), onPressed: controller.isScanning.value ? null : controller.startScan, )), ], ), body: Column( children: [ // 状态消息 - 使用AnimatedContainer让过渡更平滑 Obx(() => AnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.all(8), width: double.infinity, color: Colors.grey[200], child: Text( controller.statusMessage.value, style: const TextStyle(fontSize: 14), ), )), // 根据连接状态显示不同的内容 Expanded( child: Obx(() { // 保存连接状态到局部变量,避免多次访问反应式变量 final isConnected = controller.isConnected.value; return isConnected ? _buildConnectedView() : _buildScanView(); }), ), ], ), ); } // 扫描视图 Widget _buildScanView() { return Column( children: [ // 扫描控制 Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Obx(() { final isScanning = controller.isScanning.value; return ElevatedButton( onPressed: isScanning ? null : controller.startScan, child: Text(isScanning ? '扫描中...' : '开始扫描'), ); }), Obx(() => ElevatedButton( onPressed: controller.isScanning.value ? controller.stopScan : null, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), child: const Text('停止扫描'), )), ], ), ), // 设备列表 - 使用RepaintBoundary提高性能 Expanded( child: RepaintBoundary( child: Obx(() { if (controller.deviceList.isEmpty) { return const Center( child: Text('没有找到设备,请开始扫描'), ); } // 仅在需要时创建列表视图 return ListView.builder( // 使用常量key避免整体重建 key: const ValueKey('device_list'), itemCount: controller.deviceList.length, itemBuilder: (context, index) { final device = controller.deviceList[index]; return Card( margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: ListTile( title: Text(device.name), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('ID: ${device.id}'), if (device.uuids.isNotEmpty) Text( 'UUID: ${device.uuids.length > 0 ? device.uuids.first : "无"}', style: const TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, maxLines: 1, ), if (device.uuids.length > 1) Text( '其他UUID: ${device.uuids.length - 1}个', style: const TextStyle(fontSize: 12), overflow: TextOverflow.ellipsis, ), ], ), trailing: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('RSSI: ${device.rssi}'), const SizedBox(height: 4), const Icon(Icons.bluetooth, size: 16), ], ), onTap: () => controller.connectToDevice(device.id), ), ); }, ); }), ), ), ], ); } // 已连接设备视图 Widget _buildConnectedView() { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 设备信息卡片 Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() => Text( '设备地址: ${controller.connectedDeviceAddress.value}', style: const TextStyle(fontWeight: FontWeight.bold), )), const SizedBox(height: 8), Obx(() => Text('电池电量: ${controller.batteryLevel.value}%')), const SizedBox(height: 4), Obx(() => Text('固件版本: ${controller.firmwareVersion.value}')), const SizedBox(height: 16), Wrap( spacing: 8, // 水平间距 runSpacing: 8, // 垂直间距 alignment: WrapAlignment.spaceBetween, children: [ SizedBox( width: 110, child: ElevatedButton( onPressed: controller.getDeviceVersion, child: const Text('获取版本'), ), ), SizedBox( width: 110, child: ElevatedButton( onPressed: controller.getBatteryInfo, child: const Text('获取电量'), ), ), SizedBox( width: 110, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, ), onPressed: controller.disconnect, child: const Text('断开连接'), ), ), ], ), ], ), ), ), const SizedBox(height: 24), // 音频控制 const Text('音频控制', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, alignment: WrapAlignment.start, children: [ SizedBox( width: 140, child: ElevatedButton( onPressed: controller.openEncoder, child: const Text('打开编码器'), ), ), SizedBox( width: 140, child: ElevatedButton( onPressed: controller.openDecoder, child: const Text('打开解码器'), ), ), ], ), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, alignment: WrapAlignment.start, children: [ SizedBox( width: 140, child: ElevatedButton( onPressed: controller.closeCodec, child: const Text('关闭编解码器'), ), ), SizedBox( width: 140, child: ElevatedButton( onPressed: controller.playA2DP, child: const Text('播放A2DP'), ), ), ], ), const SizedBox(height: 24), // 音量控制 const Text('音量控制', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), Wrap( spacing: 8, runSpacing: 8, alignment: WrapAlignment.start, children: [ SizedBox( width: 140, child: ElevatedButton( onPressed: controller.volumeUp, child: const Text('音量+'), ), ), SizedBox( width: 140, child: ElevatedButton( onPressed: controller.volumeDown, child: const Text('音量-'), ), ), ], ), ], ), ); } }