From e91c400d2f8a309b07d51e63c78b17740d44e9ea Mon Sep 17 00:00:00 2001 From: fuenmao <980740792@qq.com> Date: Tue, 10 Dec 2024 15:44:12 +0800 Subject: [PATCH] =?UTF-8?q?1.=E8=A7=86=E9=A2=91=E9=80=BB=E8=BE=91=E6=A2=B3?= =?UTF-8?q?=E7=90=86=EF=BC=88=E9=99=A4=E5=88=AB=E4=BA=BA=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=88=96=E5=8F=96=E6=B6=88=E5=8F=91=E8=A8=80?= =?UTF-8?q?=E8=BF=98=E6=9C=89=E5=BE=85=E5=95=86=E6=A6=B7=EF=BC=89=202.?= =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E8=AE=B2=E8=AF=9D=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/main/AndroidManifest.xml | 3 + .../lib/pages/metting/meeting_main_logic.dart | 218 +++++++--- .../lib/pages/metting/meeting_main_state.dart | 11 +- .../lib/pages/metting/meeting_main_view.dart | 385 +++++++++--------- 4 files changed, 386 insertions(+), 231 deletions(-) diff --git a/wgshare/android/app/src/main/AndroidManifest.xml b/wgshare/android/app/src/main/AndroidManifest.xml index 870a059..b1ec4c8 100644 --- a/wgshare/android/app/src/main/AndroidManifest.xml +++ b/wgshare/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + meetingRoomUsers) async { state.users.value = meetingRoomUsers; state.cacheUsers.value = meetingRoomUsers; - // doHttpGetTvAnchor(); + doHttpGetTvAnchor(); } /// 启动计时 @@ -167,58 +167,146 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ Future doHttpGetTvAnchor() async { BaseStructureResult res = await getClient().getTvAnchor(state.roomNumber.value); state.remoteUid.value = res.data!.toString(); + if(res.data!.toString().length != 9){ + // 摄像头 + // 判断自己是不是全员观看主播 + if(state.remoteUid.value == UserStore.to.userInfoEntity.value!.uid) { + state.isSelf.value = true; + }else{ + state.isSelf.value = false; + } + + if(state.isSelf.value == true){ + // 如果自己是全员观看主播 + if(state.isOpenCamera.value == true){ + // 有发言权限且开了摄像头的时候才切换页面到视频状态 + changePageState(1); + state.floating.value?.close(); + }else{ + // 否则切换页面到语音状态 + changePageState(0); + } + }else{ + // 如果自己不是全员观看主播 + var isCurrentUserIsCamera = false; + // 遍历当前会议室用户列表获取对应用户判断 + for(var i = 0; i < state.cacheUsers.value.length; i++){ + if(state.remoteUid.value == state.cacheUsers.value[i].uid && state.cacheUsers.value[i].enableCamera == true){ + isCurrentUserIsCamera = true; + } + } + if(isCurrentUserIsCamera == true){ + changePageState(1); + }else{ + changePageState(0); + } + } + }else{ + // 共享屏幕 + // 判断是不是自己在共享 + if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){ + state.isSelf.value = false; + }else{ + state.isSelf.value = true; + } + + // 不是自己在共享才切换页面状态 + if(state.isSelf.value == false){ + changePageState(1); + } + } + /*if(res.data!.toString().length != 9){ if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.uid) { state.isSelf.value = false; }else{ state.isSelf.value = true; } - }else{ - if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){ - if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.uid) { - state.isSelf.value = false; + if(state.isSelf.value == true){ + if(state.isOpenCamera.value == true){ + changePageState(1); }else{ - state.isSelf.value = true; + changePageState(0); + } + state.floating.value?.close(); + }else{ + var isCurrentUserIsCamera = false; + for(var i = 0; i < state.cacheUsers.value.length; i++){ + if(state.remoteUid.value == state.cacheUsers.value[i].uid && state.cacheUsers.value[i].enableCamera == true){ + isCurrentUserIsCamera = true; + } + } + if(isCurrentUserIsCamera == true){ + changePageState(1); + }else{ + changePageState(0); } } - } - if(state.isSelf.value == true){ - state.floating.value?.close(); - } - Future.delayed(const Duration(milliseconds: 1000), () { - changePageState(1); - }); + }else{ + if(state.remoteUid.value != UserStore.to.userInfoEntity.value!.screenShareId){ + state.isSelf.value = false; + }else{ + state.isSelf.value = true; + } + + if(state.isSelf.value == false){ + changePageState(1); + } + }*/ } - /// 设置屏幕共享是否打开 - Future setScreenShareOpen(bool isOpen) async { - state.isOpenShare.value = isOpen; - if(isOpen == true){ - await getClient().setTvAnchor( - state.roomNumber.value, - UserStore.to.userInfoEntity.value!.screenShareId, - UserStore.to.userInfoEntity.value!.userName - ); - await state.rctEngine.value?.startScreenCapture(const ScreenCaptureParameters2(captureAudio: true, captureVideo: true)); - await state.rctEngine.value?.joinChannelEx( - token: state.meetingToken.value, - connection: RtcConnection(channelId: state.roomNumber.value, localUid: int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId)), - options: const ChannelMediaOptions( - publishScreenCaptureAudio: true, - publishScreenCaptureVideo: true, - clientRoleType: ClientRoleType.clientRoleBroadcaster, - )); - }else{ - await state.rctEngine.value?.stopScreenCapture(); - await state.rctEngine.value?.leaveChannelEx( - connection: RtcConnection(channelId: state.roomNumber.value, localUid: int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId)), - options: const LeaveChannelOptions( - stopMicrophoneRecording: false, - stopAllEffect: false - )); - } + /// 设置当前全员观看主播 + Future doHttpSetTvAnchor(String id) async { + await getClient().setTvAnchor( + state.roomNumber.value, + id, + UserStore.to.userInfoEntity.value!.userName + ); } + /// 启动共享屏幕 + Future startScreenCapture() async { + debugPrint("wgs输出===:RTC-启动屏幕共享"); + state.isOpenShare.value = true; + final shareShareUid = int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId); + await state.rctEngine.value?.setAudioScenario(AudioScenarioType.audioScenarioGameStreaming); + await state.rctEngine.value?.startScreenCapture(const ScreenCaptureParameters2(captureAudio: true, captureVideo: true)); + await state.rctEngine.value?.joinChannelEx( + token: state.meetingToken.value, + connection: RtcConnection(channelId: state.roomNumber.value, localUid: shareShareUid), + options: const ChannelMediaOptions( + autoSubscribeVideo: false, + autoSubscribeAudio: false, + publishScreenTrack: true, + publishSecondaryScreenTrack: true, + publishCameraTrack: false, + publishMicrophoneTrack: false, + publishScreenCaptureAudio: true, + publishScreenCaptureVideo: true, + clientRoleType: ClientRoleType.clientRoleBroadcaster, + )); + doHttpSetTvAnchor(UserStore.to.userInfoEntity.value!.screenShareId); + } + + /// 停止共享屏幕 + Future stopScreenCapture() async { + debugPrint("wgs输出===:RTC-停止屏幕共享"); + state.isOpenShare.value = false; + final shareShareUid = int.tryParse(UserStore.to.userInfoEntity.value!.screenShareId); + await state.rctEngine.value?.stopScreenCapture(); + await state.rctEngine.value?.leaveChannelEx( + connection: RtcConnection( + channelId: state.roomNumber.value, + localUid: shareShareUid + ), + options: const LeaveChannelOptions( + stopMicrophoneRecording: false, + stopAllEffect: false + )); + doHttpSetTvAnchor(UserStore.to.userInfoEntity.value!.uid); + } + + /// ------------------------------------------------------------------------------signalR Socket相关 /// Socket长连接 Future signalRSocket() async { @@ -271,6 +359,9 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ state.isSpeak.value = false; state.isOpenMicrophone.value = false; state.isOpenCamera.value = false; + state.isOpenShare.value = false; + state.isSelf.value = false; + state.remoteUid.value = ""; // 设置声网SDK角色为观众 setClientRole("观众"); @@ -280,9 +371,11 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ stopPreview(); // 关闭本地预览悬浮窗 state.floating.value?.close(); + // 切换页面状态 changePageState(0); - state.isSelf.value = false; - state.remoteUid.value = ""; + // 停止共享屏幕 + stopScreenCapture(); + debugPrint("wgs输出===:Socket-关闭发言权限:观众"); } @@ -448,6 +541,13 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ stopPreview(); // 关闭本地预览悬浮窗 state.floating.value?.close(); + }else{ + if(meetingRoomUser.uid == state.remoteUid.value || meetingRoomUser.screenShareId == state.remoteUid.value){ + if(state.isOpenCamera.value == true){ + state.remoteUid.value = ""; + changePageState(0); + } + } } } }); @@ -474,6 +574,7 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ /// 离开会议室 Future leaveMeetingToSocket() async { await state.hubConnection.value?.invoke("levelChannel", args: [state.roomNumber.value]); + state.hubConnection.value?.stop(); } /// 会议室发送消息 @@ -577,14 +678,24 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ if(speakers.isNotEmpty){ for(AudioVolumeInfo avi in speakers){ for(MeetingRoomUser mru in state.cacheUsers.value){ + // 用于更改语音布局里的用户列表麦克风 if(avi.uid == 0){ - debugPrint("wgs输出===:RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}"); + //debugPrint("wgs输出===:RTC-用户音量提示(自己):${CountMicrophoneVolume.getVolume(avi.volume!)}"); mru.volume = CountMicrophoneVolume.getVolume(avi.volume!); state.microphoneVolume.value = CountMicrophoneVolume.getVolume(avi.volume!); + }else{ if(avi.uid.toString() == mru.uid){ - debugPrint("wgs输出===:RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}"); + //debugPrint("wgs输出===:RTC-用户音量提示(远端用户):${speakers[0].uid}--${speakers[0].volume}"); mru.volume = CountMicrophoneVolume.getVolume(avi.volume!); + + if(avi.volume != 0){ + state.spokesman.value = mru.userName; + state.spokesmanVolume.value = CountMicrophoneVolume.getVolume(avi.volume!); + }else{ + state.spokesman.value = ""; + state.spokesmanVolume.value = 0; + } } } } @@ -601,9 +712,24 @@ class MeetingMainLogic extends GetxController with RequestToolMixin{ debugPrint("wgs输出===:RTC-切换用户角色为:${newRole == ClientRoleType.clientRoleBroadcaster ? "主播" : "观众"}"); }, - // token即将在30秒内过期 + // token即将在30秒内过期回调 onTokenPrivilegeWillExpire: (RtcConnection connection, String token){ doHttpGetMeetingToken(false); + }, + + // 本地视频状态发生改变回调 + onLocalVideoStateChanged: (VideoSourceType source, LocalVideoStreamState state, LocalVideoStreamReason reason){ + debugPrint("wgs输出===:RTC-本地视频状态发生改变:$source--$state--$reason"); + }, + + // 获取设备权限出错回调 + onPermissionError: (PermissionType permissionType){ + debugPrint("wgs输出===:RTC-获取设备权限出错:$permissionType"); + if(permissionType == PermissionType.screenCapture){ + // 获取共享屏幕出错 + state.isOpenShare.value = false; + stopScreenCapture(); + } } ), ); diff --git a/wgshare/lib/pages/metting/meeting_main_state.dart b/wgshare/lib/pages/metting/meeting_main_state.dart index 0531ad1..f487389 100644 --- a/wgshare/lib/pages/metting/meeting_main_state.dart +++ b/wgshare/lib/pages/metting/meeting_main_state.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_floating/floating/floating.dart'; import 'package:get/get.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart'; +import 'package:preload_page_view/preload_page_view.dart'; import 'package:signalr_core/signalr_core.dart'; import '../../common/models/meeting_room_info.dart'; @@ -19,6 +20,7 @@ class MeetingMainState { late TextEditingController memberNameSearchController = TextEditingController(); late TextEditingController sendMsgController = TextEditingController(); + late PreloadPageController pageController = PreloadPageController(initialPage: 0); late Rx floating = Rx(null); late Rx context = Rx(null); @@ -64,12 +66,17 @@ class MeetingMainState { late RxDouble microphoneVolume = 0.0.obs; /// 是否打开摄像头 late RxBool isOpenCamera = false.obs; + /// 是否启动屏幕共享摄像头 + late RxBool isOpenShare = false.obs; /// 当前视频主播ID late RxString remoteUid = "".obs; /// 当前主播是否是自己 late RxBool isSelf = false.obs; - /// 是否启动屏幕共享摄像头 - late RxBool isOpenShare = false.obs; + + /// 当前谁在说话 + late RxString spokesman = "".obs; + /// 当前说话音量 + late RxDouble spokesmanVolume = 0.0.obs; /// 聊天数据 late RxList meetingRoomMsgs = RxList([]); diff --git a/wgshare/lib/pages/metting/meeting_main_view.dart b/wgshare/lib/pages/metting/meeting_main_view.dart index 9092457..8816198 100644 --- a/wgshare/lib/pages/metting/meeting_main_view.dart +++ b/wgshare/lib/pages/metting/meeting_main_view.dart @@ -518,9 +518,9 @@ class MeetingMainPageState extends State { onTap: () { if (state.isSpeak.value == true) { if (state.isOpenShare.value == true) { - logic.setScreenShareOpen(false); + logic.stopScreenCapture(); } else { - logic.setScreenShareOpen(true); + logic.startScreenCapture(); } } }, @@ -1517,6 +1517,7 @@ class MeetingMainPageState extends State { /// 对应页数的界面-全员观看是别人时 Widget returnPageToOther(int position){ + debugPrint("wgs输出===:全员观看是别人时布局"); var pageList = []; /// 大屏 pageList.add(Stack( @@ -1559,13 +1560,209 @@ class MeetingMainPageState extends State { fontSize: 10.sp, color: ColorUtil.Color_185_184_184), ), - Image.asset( - 'assets/images/meeting_main_speak2.png', + SizedBox( width: 20.w, height: 20.h, + child: LiquidCustomProgressIndicator( + value: + state.spokesmanVolume.value, + valueColor: + const AlwaysStoppedAnimation( + ColorUtil + .Color_2_177_136), + backgroundColor: + ColorUtil.Color_255_255_255, + direction: Axis.vertical, + shapePath: ViewSvgPath + .getMicrpphonePath()), ), Text( - '晓晓', + state.spokesman.value, + style: TextStyle( + fontSize: 10.sp, + color: ColorUtil.Color_185_184_184), + ) + ], + ), + ), + ), + ], + )); + /// gridview + pageList.add(Container( + color: ColorUtil.Color_57_57_57, + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 0.8, + crossAxisSpacing: 0), + itemCount: state.cacheUsers.value.length, + itemBuilder: (BuildContext ctx, index) { + return Stack( + children: [ + state.cacheUsers.value[index].enableCamera == true ? state.cacheUsers.value[index].uid == + UserStore.to.userInfoEntity.value!.uid + ? AgoraVideoView( + controller: VideoViewController( + rtcEngine: state.rctEngine.value!, + canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd) + ), + ) + : AgoraVideoView( + controller: VideoViewController.remote( + rtcEngine: state.rctEngine.value!, + canvas: VideoCanvas( + uid: int.tryParse( + state.cacheUsers.value[index].uid), setupMode: VideoViewSetupMode.videoViewSetupAdd), + connection: RtcConnection( + channelId: state.roomNumber.value), + ), + ) + : + Container( + color: Colors.amber, + ), + Positioned( + left: 4, + bottom: 4, + child: Row( + children: [ + Visibility( + visible: state.cacheUsers.value[index].uid == UserStore.to.userInfoEntity.value!.uid, + child: Image.asset( + 'assets/images/meeting_main_own.png', + width: 24.w, + height: 24.h, + ), + ), + Container( + height: 20, + margin: const EdgeInsets.only(left: 4), + padding: + const EdgeInsets.only(left: 4, right: 4), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(2), + color: ColorUtil.Color_0_0_0_96), + child: state.cacheUsers.value[index].enableMicr == true + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + SizedBox( + width: 20.w, + height: 20.h, + child: LiquidCustomProgressIndicator( + value: + state.cacheUsers.value[index] + .volume ?? + 0.0, + valueColor: + const AlwaysStoppedAnimation( + ColorUtil + .Color_2_177_136), + backgroundColor: + ColorUtil.Color_255_255_255, + direction: Axis.vertical, + shapePath: ViewSvgPath + .getMicrpphonePath()), + ), + + ], + ) + : Row( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/meeting_main_microphone_open.png', + width: 20.w, + height: 20.h, + ), + Text( + state.cacheUsers.value[index].userName, + style: TextStyle( + fontSize: 12.sp, + color: ColorUtil + .Color_255_255_255), + ) + ], + ), + ) + ], + ), + ) + ], + ); + }), + )); + return pageList[position]; + } + + /// 对应页数的界面-全员观看是自己时 + Widget returnPageSelf(int position){ + debugPrint("wgs输出===:全员观看是自己时布局"); + var pageList = []; + /// 大屏 + pageList.add(Stack( + alignment: Alignment.center, + children: [ + AgoraVideoView( + controller: VideoViewController( + rtcEngine: state.rctEngine.value!, + canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd), + ), + ), + /*Positioned( + bottom: 110, + child: GestureDetector( + child: Image.asset( + 'assets/images/meeting_main_hang_up.png', + width: 50.w, + height: 50.h, + ), + onTap: () { + }, + ), + ),*/ + Positioned( + top: 16, + right: 16, + child: Container( + height: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: ColorUtil.Color_0_0_0_96), + padding: const EdgeInsets.only(left: 12, right: 12), + child: Row( + children: [ + Text( + '正在讲话:', + style: TextStyle( + fontSize: 10.sp, + color: ColorUtil.Color_185_184_184), + ), + SizedBox( + width: 20.w, + height: 20.h, + child: LiquidCustomProgressIndicator( + value: + state.spokesmanVolume.value, + valueColor: + const AlwaysStoppedAnimation( + ColorUtil + .Color_2_177_136), + backgroundColor: + ColorUtil.Color_255_255_255, + direction: Axis.vertical, + shapePath: ViewSvgPath + .getMicrpphonePath()), + ), + Text( + state.spokesman.value, style: TextStyle( fontSize: 10.sp, color: ColorUtil.Color_185_184_184), @@ -1696,182 +1893,4 @@ class MeetingMainPageState extends State { return pageList[position]; } - /// 对应页数的界面-全员观看是自己时 - Widget returnPageSelf(int position){ - var pageList = []; - /// 大屏 - pageList.add(Stack( - alignment: Alignment.center, - children: [ - AgoraVideoView( - controller: VideoViewController( - rtcEngine: state.rctEngine.value!, - canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd), - ), - ), - /*Positioned( - bottom: 110, - child: GestureDetector( - child: Image.asset( - 'assets/images/meeting_main_hang_up.png', - width: 50.w, - height: 50.h, - ), - onTap: () { - }, - ), - ),*/ - Positioned( - top: 16, - right: 16, - child: Container( - height: 30, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: ColorUtil.Color_0_0_0_96), - padding: const EdgeInsets.only(left: 12, right: 12), - child: Row( - children: [ - Text( - '正在讲话:', - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_185_184_184), - ), - Image.asset( - 'assets/images/meeting_main_speak2.png', - width: 20.w, - height: 20.h, - ), - Text( - '晓晓', - style: TextStyle( - fontSize: 10.sp, - color: ColorUtil.Color_185_184_184), - ) - ], - ), - ), - ), - ], - )); - /// gridview - pageList.add(Container( - color: ColorUtil.Color_57_57_57, - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: 0.8, - crossAxisSpacing: 0), - itemCount: state.cacheUsers.value.length, - itemBuilder: (BuildContext ctx, index) { - return Stack( - children: [ - state.cacheUsers.value[index].enableCamera == true ? state.cacheUsers.value[index].uid == - UserStore.to.userInfoEntity.value!.uid - ? AgoraVideoView( - controller: VideoViewController( - rtcEngine: state.rctEngine.value!, - canvas: const VideoCanvas(uid: 0, setupMode: VideoViewSetupMode.videoViewSetupAdd) - ), - ) - : AgoraVideoView( - controller: VideoViewController.remote( - rtcEngine: state.rctEngine.value!, - canvas: VideoCanvas( - uid: int.tryParse( - state.cacheUsers.value[index].uid), setupMode: VideoViewSetupMode.videoViewSetupAdd), - connection: RtcConnection( - channelId: state.roomNumber.value), - ), - ) - : - Container( - color: Colors.amber, - ), - Positioned( - left: 4, - bottom: 4, - child: Row( - children: [ - Visibility( - visible: state.cacheUsers.value[index].uid == UserStore.to.userInfoEntity.value!.uid, - child: Image.asset( - 'assets/images/meeting_main_own.png', - width: 24.w, - height: 24.h, - ), - ), - Container( - height: 20, - margin: const EdgeInsets.only(left: 4), - padding: - const EdgeInsets.only(left: 4, right: 4), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(2), - color: ColorUtil.Color_0_0_0_96), - child: state.cacheUsers.value[index].enableMicr == true - ? Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - SizedBox( - width: 20.w, - height: 20.h, - child: LiquidCustomProgressIndicator( - value: - state.cacheUsers.value[index] - .volume ?? - 0.0, - valueColor: - const AlwaysStoppedAnimation( - ColorUtil - .Color_2_177_136), - backgroundColor: - ColorUtil.Color_255_255_255, - direction: Axis.vertical, - shapePath: ViewSvgPath - .getMicrpphonePath()), - ), - Text( - state.cacheUsers.value[index].userName, - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil - .Color_255_255_255), - ) - ], - ) - : Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/meeting_main_microphone_open.png', - width: 20.w, - height: 20.h, - ), - Text( - state.cacheUsers.value[index].userName, - style: TextStyle( - fontSize: 12.sp, - color: ColorUtil - .Color_255_255_255), - ) - ], - ), - ) - ], - ), - ) - ], - ); - }), - )); - return pageList[position]; - } }