From 2cac572702c324396dc5d9d47aab83cc774ad92f Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Sat, 1 Aug 2026 04:04:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(iOS):=20=E4=BF=AE=E5=A4=8D=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E6=98=BE=E7=A4=BA=E6=A8=A1=E5=BC=8F=E4=B8=BA=E5=A1=AB?= =?UTF-8?q?=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将远端视频渲染视图和内容视图的视频内容模式从 `.fit` 改为 `.fill`,并调整控制面板布局,将录制与断开按钮单独成行,提升界面利用率与操作体验。 --- .../Views/ContentView.swift | 108 ++++++++++-------- .../Views/RemoteVideoView.swift | 2 +- 2 files changed, 60 insertions(+), 50 deletions(-) diff --git a/webrtc_controller_ios/web_rtc_controller_ios/Views/ContentView.swift b/webrtc_controller_ios/web_rtc_controller_ios/Views/ContentView.swift index 436d02c..7037de0 100644 --- a/webrtc_controller_ios/web_rtc_controller_ios/Views/ContentView.swift +++ b/webrtc_controller_ios/web_rtc_controller_ios/Views/ContentView.swift @@ -156,64 +156,72 @@ private struct ControlPanelView: View { } private var topBar: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 12) { - Text(viewModel.statusText) - .font(.footnote) - .foregroundColor(.green) - .lineLimit(1) + VStack(spacing: 6) { + // 第一行:状态 + 串流模式切换 + 分辨率 + 帧率 + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 12) { + Text(viewModel.statusText) + .font(.footnote) + .foregroundColor(.green) + .lineLimit(1) + .fixedSize() + + // 串流模式切换(WebRTC / 自编码) + Toggle(isOn: Binding( + get: { viewModel.streamMode == .selfCodec }, + set: { viewModel.toggleStreamMode($0) })) { + Text("自编码") + .font(.footnote) + .foregroundColor(.white) + } + .toggleStyle(.switch) .fixedSize() - // 串流模式切换(WebRTC / 自编码) - Toggle(isOn: Binding( - get: { viewModel.streamMode == .selfCodec }, - set: { viewModel.toggleStreamMode($0) })) { - Text("自编码") - .font(.footnote) - .foregroundColor(.white) - } - .toggleStyle(.switch) - .fixedSize() - - // 分辨率选择 - Menu { - ForEach(ResolutionOption.all) { option in - Button { - viewModel.selectResolution(option) - } label: { - if option == viewModel.selectedResolution { - Label(option.title, systemImage: "checkmark") - } else { - Text(option.title) + // 分辨率选择 + Menu { + ForEach(ResolutionOption.all) { option in + Button { + viewModel.selectResolution(option) + } label: { + if option == viewModel.selectedResolution { + Label(option.title, systemImage: "checkmark") + } else { + Text(option.title) + } } } + } label: { + Label(viewModel.selectedResolution.title, systemImage: "rectangle.compress.vertical") + .font(.footnote) + .fixedSize() } - } label: { - Label(viewModel.selectedResolution.title, systemImage: "rectangle.compress.vertical") - .font(.footnote) - .fixedSize() - } - // 帧率选择(档位来自被控端 REPORT_RESOLUTION 上报) - Menu { - ForEach(viewModel.fpsOptions, id: \.self) { fps in - Button { - viewModel.selectFps(fps) - } label: { - if fps == viewModel.currentFps { - Label("\(fps)fps", systemImage: "checkmark") - } else { - Text("\(fps)fps") + // 帧率选择(档位来自被控端 REPORT_RESOLUTION 上报) + Menu { + ForEach(viewModel.fpsOptions, id: \.self) { fps in + Button { + viewModel.selectFps(fps) + } label: { + if fps == viewModel.currentFps { + Label("\(fps)fps", systemImage: "checkmark") + } else { + Text("\(fps)fps") + } } } + } label: { + Label(viewModel.currentFps > 0 ? "\(viewModel.currentFps)fps" : "帧率", + systemImage: "speedometer") + .font(.footnote) + .fixedSize() } - } label: { - Label(viewModel.currentFps > 0 ? "\(viewModel.currentFps)fps" : "帧率", - systemImage: "speedometer") - .font(.footnote) - .fixedSize() } + .padding(.horizontal, 12) + .padding(.vertical, 6) + } + // 第二行:录制 + 断开(当前行下方) + HStack(spacing: 12) { // 录制远端视频(MP4) Button { if viewModel.isRecording { @@ -241,9 +249,11 @@ private struct ControlPanelView: View { .buttonStyle(.borderedProminent) .tint(.red) .controlSize(.small) + + Spacer() } .padding(.horizontal, 12) - .padding(.vertical, 6) + .padding(.bottom, 6) } .background(Color(white: 0.1)) } @@ -269,7 +279,7 @@ private struct ControlPanelView: View { viewModel.sendSwipe(x1: x1, y1: y1, x2: x2, y2: y2, duration: duration) }) } - .aspectRatio(viewModel.videoAspect, contentMode: .fit) + .aspectRatio(viewModel.videoAspect, contentMode: .fill) .frame(maxWidth: .infinity, maxHeight: .infinity) // 录制中指示(左上角红点) diff --git a/webrtc_controller_ios/web_rtc_controller_ios/Views/RemoteVideoView.swift b/webrtc_controller_ios/web_rtc_controller_ios/Views/RemoteVideoView.swift index 7a8e933..c7f3684 100644 --- a/webrtc_controller_ios/web_rtc_controller_ios/Views/RemoteVideoView.swift +++ b/webrtc_controller_ios/web_rtc_controller_ios/Views/RemoteVideoView.swift @@ -7,7 +7,7 @@ struct RemoteVideoView: UIViewRepresentable { let videoView: RTCMTLVideoView func makeUIView(context: Context) -> RTCMTLVideoView { - videoView.videoContentMode = .scaleAspectFit + videoView.videoContentMode = .scaleAspectFill return videoView }