Flutter如何基于socket.io及数据库实时数据动态修改widget颜色
你当前使用的FutureBuilder仅会在页面初始化时发起一次数据请求,无法监听socket.io推送的实时数据变更,因此无法实现动态更新效果。你需要改用StreamBuilder监听socket的实时数据流,配合状态更新实现颜色自动变更。
步骤1:在roomService中创建Socket实时数据流
首先在你的roomService类中添加Stream控制器,监听socket.io的推送事件,将收到的实时数据同步到Stream中。
import 'dart:async'; import 'package:socket_io_client/socket_io_client.dart' as IO; class RoomService { // 定义Stream控制器,用于推送房间数据更新 final StreamController<Room> _roomStreamController = StreamController<Room>.broadcast(); late IO.Socket socket; // 初始化socket连接 void initSocket() { socket = IO.io('你的socket服务地址', <String, dynamic>{ 'transports': ['websocket'], 'autoConnect': false, }); socket.connect(); // 监听socket推送的房间数据更新事件,事件名需和后端保持一致 socket.on('roomDataUpdated', (data) { // 将收到的json数据解析为Room对象 Room updatedRoom = Room.fromJson(data); // 将新数据推送至Stream _roomStreamController.sink.add(updatedRoom); }); } // 暴露Stream给外部监听 Stream<Room> get roomStream => _roomStreamController.stream; // 原有获取房间数据的方法保留,用于首次加载 Future<Room> getRoom() async { // 原有逻辑不变 } // 页面销毁时释放资源 void dispose() { socket.disconnect(); _roomStreamController.close(); } }
步骤2:修改页面代码,替换FutureBuilder为StreamBuilder
将原有的FutureBuilder替换为StreamBuilder,监听roomService的实时数据流,同时根据业务规则修改Card的颜色判断逻辑:
// 首先在页面的initState中初始化socket @override void initState() { super.initState(); roomService.initSocket(); } @override void dispose() { roomService.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return StreamBuilder<Room>( // 监听socket推送的实时数据流 stream: roomService.roomStream, builder: (context, snapshot){ if(snapshot.hasData){ return GridView.builder( itemCount: snapshot.data!.data.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5), itemBuilder: (context, index){ var values = snapshot.data!.data[index]; return GestureDetector( onTap: (){ Navigator.push(context, CupertinoModalPopupRoute(builder: (context)=>RoomDetailScreen(20, 30, 20+30))); }, child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.r), ), // 在这里根据业务规则判断颜色,示例:房间状态为空闲显示绿色,占用显示红色 color: values['status'] == 'free' ? Colors.green : Colors.red, elevation: 6, child: Container( alignment: Alignment.center, child:Text( "${values['RType']}", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16.sp, color: AppColors.whiteSec), ), ), ), ); }, ); }else if(snapshot.hasError){ return Center( child: Column( children: const [ Center(child: Icon(Icons.error,color: AppColors.yellowPri,)), ], ), ); } return const Center(child: CircularProgressIndicator()); } ); }
注意事项
- 颜色判断逻辑可根据你的实际业务字段调整,比如根据RType、占用人数等参数判断
- 页面销毁时必须调用dispose方法释放socket和Stream资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Deowan
相关产品推荐
相关产品推荐

