我正在创建一个应用,其主 UI 是 WKWebView,SwiftUI 仅用于应用的零散部分。我在使用 SwiftUI 系统 UI 时遇到了一些问题TabView
。运行此示例应用时,出现了一些我无法解释的行为。
enum Page: String, Hashable, CaseIterable, Identifiable {
case settings = "gear"
case radio = "radio"
case connect = "dot.radiowaves.right"
var id: String { rawValue }
}
struct RandomColorHostedWebView: UIViewRepresentable {
let webView: WKWebView
init() {
// Clear cache to be extra sure https://stackoverflow.com/a/34376943/3833632
WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
let webConfiguration = WKWebViewConfiguration()
self.webView = WKWebView(frame: .zero, configuration: webConfiguration)
let urlRequest = URLRequest(url: URL(string: "https://randomcolour.com")!)
self.webView.load(urlRequest)
}
func makeUIView(context: Context) -> UIView {
return webView
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
struct ContentView: View {
let pages = Page.allCases
let randomColor: RandomColorHostedWebView
init() {
randomColor = RandomColorHostedWebView()
}
var body: some View {
TabView {
ForEach(pages) { page in
randomColor
.tag(page)
.tabItem {
Label(page.rawValue, systemImage: page.rawValue)
}
}
}
}
}
运行此程序,你会发现每次点击标签页都会触发刷新动画,但不会加载新的颜色。此外,当你返回之前访问过的标签页时,页面会显示空白。
我无法解释这种现象。 (我很想知道为什么会发生这种情况)
话虽如此,我假设原因是 SwiftUI 不知道每个 tabItem 父视图都是相同的视图,因为它们具有不同的结构标识。
因此,我只能寻找一种解决方法,要么使 TabView 的背景清晰,以便我可以使用ZStack
,要么将TabView
高度限制为仅限选项卡内容,以便我可以使用VStack
,或者其他方法。
现有的解决方案尝试移除 TabView 的背景,但似乎无效。我同意一位评论者的观点,即该解决方案在更高版本的操作系统中似乎已失效。
var body: some View {
ZStack {
randomColor
TabView {
ForEach(pages) { page in
Color.clear
// https://stackoverflow.com/questions/63178381/make-tabview-background-transparent
.background(BackgroundHelper())
.tag(page)
.tabItem {
Label(page.rawValue, systemImage: page.rawValue)
}
}
}
}
}
你的
UIViewRepresentable
实现不正确。你应该始终在 中返回视图的新实例makeUIView
。在当前实现中,你只有一个实例WKWebView
。当你在标签页之间切换时,SwiftUI 会将其添加
WKWebView
为不同标签页的子视图。显然,一个标签页UIView
只能有一个父视图,因此当你移动到另一个标签页时,它WKWebView
会从上一个标签页中移除。当你返回到已访问的标签页时,它WKWebView
不会被添加回来,因为 SwiftUI 从一开始就不希望它被移除。这是一个更正确的实现:
链接帖子
BackgroundHelper
中的 可以稍微修改一下,使用UIViewControllerRepresentable
- 向上移动UIViewController
层级而不是UIView
层级。当然,这并不能保证将来不会出现问题。然后你可以写
我使用了
ignoresSafeArea
和toolbarBackgroundVisibility
来让它看起来更美观。根据你实际显示的网页内容,你可能不想忽略底部安全区域(例如,你想把网页视图放在标签栏正上方),在这种情况下,你可以这样做: