我通过旋转选项卡视图和内部视图制作了垂直滚动选项卡视图。这样做时,视图会向右移动约 10.5 点(在更大和更小的设备上或多或少)。我可以简单地添加一个偏移量,将视图向右移动 10.5 点,但这在所有设备上看起来并不好。
单独显示视图而不使用任何选项卡视图看起来不错。就在我将视图放入垂直 tabView 后,它看起来向右移动了。我希望了解一种更有效的居中方法,而不是基本的偏移修改器。您可以忽略除 AllVideoView 中的代码之外的所有代码。
import SwiftUI
import WebKit
import UIKit
struct AllVideoView: View {
@State private var selected = ""
@State private var arr = ["-q6-DxWZnlQ", "Bp3iu47RRJQ", "lXJdgDjw1Ks", "It3ecCpuzgc", "7WNJjr8QM1w"]
var body: some View {
ZStack {
Color.black.edgesIgnoringSafeArea([.bottom, .top])
TabView(selection: $selected){
ForEach(arr, id: \.self){ id in
SingleVideoView(link: id).tag(id)
}
.rotationEffect(.init(degrees: -90))
.frame(width: widthOrHeight(width: true), height: widthOrHeight(width: false))
}
//.offset(x: -10.5) // this makes it align right
.frame(width: widthOrHeight(width: false), height: widthOrHeight(width: true))
.rotationEffect(.init(degrees: 90))
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
struct SingleVideoView: View {
let link: String
@State private var viewIsShowing = false
@State private var isVideoPlaying = false
var body: some View {
ZStack {
Color.black
SmartReelView(link: link, isPlaying: $isVideoPlaying, viewIsShowing: $viewIsShowing)
Button("", action: {}).disabled(true)
Color.gray.opacity(0.001)
.onTapGesture {
isVideoPlaying.toggle()
}
}
.ignoresSafeArea()
.onDisappear {
isVideoPlaying = false
viewIsShowing = false
}
.onAppear {
viewIsShowing = true
isVideoPlaying = true
}
}
}
struct SmartReelView: UIViewRepresentable {
let link: String
@Binding var isPlaying: Bool
@Binding var viewIsShowing: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.navigationDelegate = context.coordinator
let userContentController = WKUserContentController()
webView.configuration.userContentController = userContentController
loadInitialContent(in: webView)
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
var jsString = """
isPlaying = \((isPlaying) ? "true" : "false");
watchPlayingState();
"""
uiView.evaluateJavaScript(jsString, completionHandler: nil)
}
class Coordinator: NSObject, WKNavigationDelegate {
var parent: SmartReelView
init(_ parent: SmartReelView) {
self.parent = parent
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if self.parent.viewIsShowing {
webView.evaluateJavaScript("clickReady()", completionHandler: nil)
}
}
}
private func loadInitialContent(in webView: WKWebView) {
let embedHTML = """
<style>
body {
margin: 0;
background-color: black;
}
.iframe-container iframe {
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
<div class="iframe-container">
<div id="player"></div>
</div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
var isPlaying = false;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
width: '100%',
videoId: '\(link)',
playerVars: { 'playsinline': 1, 'controls': 0},
events: {
'onStateChange': function(event) {
if (event.data === YT.PlayerState.ENDED) {
player.seekTo(0);
player.playVideo();
}
}
}
});
}
function clickReady() {
player.playVideo();
}
function watchPlayingState() {
if (isPlaying) {
player.playVideo();
} else {
player.pauseVideo();
}
}
</script>
"""
webView.scrollView.isScrollEnabled = false
webView.loadHTMLString(embedHTML, baseURL: nil)
}
}
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
及其内部的视图来创建垂直滚动选项卡,旋转可能会导致一些空间调整,从而改变视图。这种转变就是您所经历的向右移动 10.5 点的情况。
为了使垂直
TabView
在不同屏幕尺寸上保持一致,请考虑以下替代方案:
GeometryReader
获取父视图的尺寸。然后,您可以动态计算偏移以确保其居中。
GeometryReader { geometry in
TabView(selection: $selected) {
// your code
}
.rotationEffect(.init(degrees: 90))
.offset(x: -(geometry.size.width - geometry.size.height) / 2)
}
另请参阅“如何在 SwiftUI 中使用 Geometry Reader”以获取说明。
此外,请确保内部视图和旋转的
TabView
的框架的定义方式不留有此类移动的空间。仔细检查您是否在旋转之后而不是之前定义框架。
.alignmentGuide
根据 TabView
的尺寸调整内部视图的水平对齐方式。
假设您想根据某些计算的偏移量移动视图 (
calculatedOffset
)。
首先,您将定义一个
HorizontalAlignment
:
extension HorizontalAlignment {
private enum MyAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[HorizontalAlignment.center]
}
}
static let myAlignment = HorizontalAlignment(MyAlignment.self)
}
然后,您可以将此自定义对齐指南应用到您的
TabView
,如下所示:
TabView(selection: $selected) {
// Your existing code
}
.rotationEffect(.init(degrees: 90))
.alignmentGuide(HorizontalAlignment.myAlignment) { d in
// calculatedOffset would be the value you have determined you need to move your view by
let calculatedOffset: CGFloat = 10.5 // replace this with your calculated value
return d[HorizontalAlignment.center] - calculatedOffset
}
最后,您需要确保您的
ZStack
使用此自定义对齐方式来定位 TabView
:
ZStack(alignment: Alignment(horizontal: .myAlignment, vertical: .center)) {
// your existing code, including the TabView
}
我使用了硬编码的
calculatedOffset
值 10.5 作为占位符。但您可以将其替换为动态计算的任何值,以根据需要调整视图的位置。
通过使用对齐参考线,您可以对视图布局实现非常细粒度的控制。这可能会帮助您解决遇到的问题。
作为替代方法,您可以将
TabView
包装在另一个视图中,然后操纵 TabView
在该容器内的位置。这样可以更好地控制其位置。
HStack {
Spacer()
TabView(selection: $selected){
// your code
}
.rotationEffect(.init(degrees: 90))
Spacer()
}
或者创建一个自定义的 SwiftUI 修饰符来封装旋转和平移逻辑,使其更容易维护和跨不同视图应用。
这个想法是根据实际尺寸动态调整视图布局,从而消除不适应不同屏幕尺寸的硬编码值。