SwiftUI中TabView旋转后子视图变形与对齐问题求助
SwiftUI垂直滚动TabView子视图变形问题解决办法
问题详情
我想做一个能垂直滚动的TabView,于是把整个TabView旋转90度,内部的SingleVideoView再反向旋转90度来保证显示正常。但这么做之后,SingleVideoView出现了变形、被拉伸的情况。单独显示这个视图(直接传入链接)时完全正常,排查后发现是TabView子视图的布局问题:去掉所有.frame修饰符,视图尺寸太小;给TabView加frame,尺寸正常但会横向拉伸。该怎么解决?
原代码如下:
import SwiftUI struct AllVideoView: View { @State private var selected = "" @Namespace private var animation var body: some View { ZStack { TabView(selection: $selected){ ForEach(arr, id: \.self){ id in SingleVideoView(link: id) .tag(id) .rotationEffect(.init(degrees: -90)) .frame(height: widthOrHeight(width: false)) } } .frame(width: widthOrHeight(width: false)) .rotationEffect(.init(degrees: 90)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .ignoresSafeArea() .background(Color.black) } } } func widthOrHeight(width: Bool) -> CGFloat { let scenes = UIApplication.shared.connectedScenes let windowScene = scenes.first as? UIWindowScene let window = windowScene?.windows.first if width { return window?.screen.bounds.width ?? 0 } else { return window?.screen.bounds.height ?? 0 } }
解决方案
问题根源在于旋转操作后的尺寸映射错误。TabView旋转90度后,宽和高的轴会互换,原来的宽度变成垂直方向的高度,原来的高度变成水平方向的宽度,之前的frame设置没有匹配这个变化,导致子视图拉伸或缩小。
修正后的代码
import SwiftUI struct AllVideoView: View { @State private var selected = "" @Namespace private var animation var body: some View { // 用GeometryReader获取当前容器的实际尺寸,比手动读屏幕更灵活 GeometryReader { proxy in let screenWidth = proxy.size.width let screenHeight = proxy.size.height TabView(selection: $selected){ ForEach(arr, id: \.self){ id in SingleVideoView(link: id) .tag(id) .rotationEffect(.degrees(-90)) // 旋转后子视图的宽对应原屏幕高度,高对应原屏幕宽度 .frame(width: screenHeight, height: screenWidth) } } // 旋转前给TabView设置反向尺寸,匹配旋转后的显示空间 .frame(width: screenHeight, height: screenWidth) .rotationEffect(.degrees(90)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .ignoresSafeArea() .background(Color.black) } } }
核心调整点
- 用GeometryReader替代手动屏幕尺寸获取:它能自动适配父容器的大小变化,比如安全区域、分屏模式,比直接读取屏幕 bounds 更可靠。
- 修正旋转前后的frame尺寸:旋转90度后,TabView的宽高需要互换,所以设置
.frame(width: screenHeight, height: screenWidth),这样旋转后刚好占满屏幕。子视图同样设置这个尺寸,确保旋转后和原屏幕尺寸匹配,不会拉伸。 - 保持宽高比(可选):如果SingleVideoView是视频类视图,通常需要固定宽高比,比如16:9,可以在子视图里添加
.aspectRatio(16/9, contentMode: .fit),强制保持比例:
SingleVideoView(link: id) .tag(id) .aspectRatio(16/9, contentMode: .fit) .rotationEffect(.degrees(-90)) .frame(width: screenHeight, height: screenWidth)
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

