Estou criando um aplicativo em que a interface principal é uma WKWebView e o SwiftUI é usado apenas para algumas funções do aplicativo. Estou com um problema ao usar a interface do sistema SwiftUI TabView
. Se você executar este aplicativo de exemplo, haverá um comportamento que não consigo explicar.
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)
}
}
}
}
}
Se você executar isso, notará que cada aba clicada gera uma animação de atualização, mas não carrega uma nova cor. Além disso, quando você retorna para uma aba que já visitou, ela estará em branco.
Esse é um comportamento que não consigo explicar. (Gostaria de entender por que isso acontece)
Dito isso, presumo que a causa seja que o SwiftUI não tem ideia de que cada uma das visualizações pai do tabItem é a mesma visualização, pois elas têm identidades estruturais diferentes.
Então, estou procurando uma solução alternativa para deixar o fundo do TabView claro para que eu possa usar um ZStack
, limitar a TabView
altura somente para o conteúdo da aba para que eu possa usar um VStack
, ou algo mais.
Esta solução existente tenta remover o fundo da TabView, mas parece não funcionar . Concordo com um comentarista que diz que a solução alternativa parece ter sido quebrada em versões posteriores do sistema operacional.
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)
}
}
}
}
}
Sua
UIViewRepresentable
implementação está incorreta. Você deve sempre retornar uma nova instância da visualização emmakeUIView
. Com a implementação atual, você só tem uma instância deWKWebView
.Conforme você alterna entre as abas, o SwiftUI as adiciona
WKWebView
como subvisualizações das diferentes abas. Obviamente, um itemUIView
só pode ter uma visualização pai, então, ao alternar para outra aba, o itemWKWebView
é removido da aba anterior. Ao retornar para uma aba visitada, o itemWKWebView
não é adicionado novamente, pois o SwiftUI não espera que ele seja removido.Aqui está uma implementação mais correta:
A
BackgroundHelper
postagem vinculada pode ser ligeiramente modificada para usar umUIViewControllerRepresentable
- subindo naUIViewController
hierarquia em vez deUIView
hierarquia. É claro que não há garantia de que isso não vá falhar no futuro.Então você pode escrever
Usei
ignoresSafeArea
etoolbarBackgroundVisibility
para melhorar a aparência. Dependendo do conteúdo da web que você estiver exibindo, talvez seja interessante ignorar a área inferior segura (ou seja, você deseja posicionar a visualização da web logo acima da barra de guias). Nesse caso, você pode fazer o seguinte: