Проблема с высотой содержимого SwiftUI WKWebView

5
Mahi008 2020-01-18 05:05.

WKWebViewПрошла неделя, когда я застрял с этой проблемой, когда у меня есть свой обычай с UIViewRepresentable

struct Webview : UIViewRepresentable {
    var webview: WKWebView?

    init() {
        self.webview = WKWebView()
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: Webview

        init(_ parent: Webview) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            print("Loading finished -- Delegate")
            webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
                print(height)
                webView.bounds.size.height = height as! CGFloat
            })
        }

    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView  {
        return webview!
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.navigationDelegate = context.coordinator
        let htmlStart = "<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\"></HEAD><BODY>"
        let htmlEnd = "</BODY></HTML>"
        let dummy_html = """
                        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut venenatis risus. Fusce eget orci quis odio lobortis hendrerit. Vivamus in sollicitudin arcu. Integer nisi eros, hendrerit eget mollis et, fringilla et libero. Duis tempor interdum velit. Curabitur</p>
                        <p>ullamcorper, nulla nec elementum sagittis, diam odio tempus erat, at egestas nibh dui nec purus. Suspendisse at risus nibh. Mauris lacinia rutrum sapien non faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum enim et augue suscipit, vitae mollis enim maximus.</p>
                        <p>Fusce et convallis ligula. Ut rutrum ipsum laoreet turpis sodales, nec gravida nisi molestie. Ut convallis aliquet metus, sit amet vestibulum risus dictum mattis. Sed nec leo vel mauris pharetra ornare quis non lorem. Aliquam sed justo</p>
                        """
        let htmlString = "\(htmlStart)\(dummy_html)\(htmlEnd)"
        uiView.loadHTMLString(htmlString, baseURL:  nil)
    }
}

и это представлено так

и проблема здесь в том, что у веб-просмотра отсутствует высота. На мой взгляд, это не отображается, если я не добавлю жестко запрограммированное frameзначение, при котором мой контент будет отключен.

Webview()
   .frame(height:300)

Я почти сталкивался с подобными вопросами, но это не помогло: /

2 answers

17
Asperi 2020-01-18 05:40.

Это сбивает с толку ScrollViewSwiftUI, который заранее ожидает известный размер контента, и UIWebViewвнутренний UIScrollView, который пытается получить размер из родительского представления ...

Итак, вот возможный подход ... передать определенный размер из веб-представления в мир SwiftUI, чтобы не использовать жесткое кодирование и вести ScrollViewсебя как плоский контент.

Сначала демонстрация результата, как я понял и смоделировал ...

Вот полный код модуля демонстрации. Протестировано и работает на Xcode 11.2 / iOS 13.2.

import SwiftUI
import WebKit

struct Webview : UIViewRepresentable {
    @Binding var dynamicHeight: CGFloat
    var webview: WKWebView = WKWebView()

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: Webview

        init(_ parent: Webview) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (height, error) in
                DispatchQueue.main.async {
                    self.parent.dynamicHeight = height as! CGFloat
                }
            })
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView  {
        webview.scrollView.bounces = false
        webview.navigationDelegate = context.coordinator
        let htmlStart = "<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\"></HEAD><BODY>"
        let htmlEnd = "</BODY></HTML>"
        let dummy_html = """
                        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut venenatis risus. Fusce eget orci quis odio lobortis hendrerit. Vivamus in sollicitudin arcu. Integer nisi eros, hendrerit eget mollis et, fringilla et libero. Duis tempor interdum velit. Curabitur</p>
                        <p>ullamcorper, nulla nec elementum sagittis, diam odio tempus erat, at egestas nibh dui nec purus. Suspendisse at risus nibh. Mauris lacinia rutrum sapien non faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum enim et augue suscipit, vitae mollis enim maximus.</p>
                        <p>Fusce et convallis ligula. Ut rutrum ipsum laoreet turpis sodales, nec gravida nisi molestie. Ut convallis aliquet metus, sit amet vestibulum risus dictum mattis. Sed nec leo vel mauris pharetra ornare quis non lorem. Aliquam sed justo</p>
                        """
        let htmlString = "\(htmlStart)\(dummy_html)\(htmlEnd)"
        webview.loadHTMLString(htmlString, baseURL:  nil)
        return webview
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
    }
}


struct TestWebViewInScrollView: View {
    @State private var webViewHeight: CGFloat = .zero
    var body: some View {
        ScrollView {
            VStack {
                Image(systemName: "doc")
                    .resizable()
                    .scaledToFit()
                    .frame(height: 300)
                Divider()
                Webview(dynamicHeight: $webViewHeight)
                    .padding(.horizontal)
                    .frame(height: webViewHeight)
            }
        }
    }
}

struct TestWebViewInScrollView_Previews: PreviewProvider {
    static var previews: some View {
        TestWebViewInScrollView()
    }
}
3
arsenius 2020-01-22 16:21.

Если я просто помещу ваш Webviewв VStackразмер, как и ожидалось. Здесь нет никакой реальной проблемы.

Хотя вы этого не заявили, наиболее вероятная причина того, что вы Webviewне занимаетесь места, заключается в том, что вы поместили эти элементы в файл ScrollView. Поскольку WKWebViewэто в основном (хотя и не подкласс) a, UIScrollViewсистема не знает, как его размер, когда он содержится в другом прокручиваемом представлении.

Например:

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView { // THIS LINE means that...
                VStack(spacing: 0.0) {
                    Color.red.aspectRatio(1.0, contentMode: .fill)
                    Text("Lorem ipsum dolor sit amet").fontWeight(.bold)
                    Webview()
                        .frame(height: 300) // ...THIS is necessary 
                }
            }
        .navigationBarItems(leading: Text("Item"))
            .navigationBarTitle("", displayMode: .inline)
        }
    }
}

Вложенные прокрутки - это не то, что вы хотите для макета, который вы все равно показывали. Вы, несомненно, хотите, чтобы это изображение и текст вверху прокручивались в сторону при прокрутке WKWebView.

Техника, которую вам нужно использовать с UIKit или SwiftUI, будет аналогичной. На данный момент я не рекомендую делать это с помощью SwiftUI.

  1. Поместите WKWebViewв контейнер (скорее всего UIViewController.view)
  2. Поместите содержимое заголовка (изображение плюс текст, который может быть в a UIHostingContainer) в этом представлении как одноуровневое изображение над веб-просмотром.
  3. Установите webView.scrollView.contentInset.topразмер вашего контента от # 2
  4. Осуществлять UIScrollViewDelegate.scrollViewDidScroll()
  5. В scrollViewDidScrollизменить положение вашего контента , чтобы соответствовать WebView - х contentOffset.

Вот одна из возможных реализаций:

WebView:

import SwiftUI
import WebKit

struct WebView : UIViewRepresentable {

    @Binding var offset: CGPoint
    var contentInset: UIEdgeInsets = .zero

    class Coordinator: NSObject, UIScrollViewDelegate {
        var parent: WebView

        init(_ parent: WebView) {
            self.parent = parent
        }

        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            var offset = scrollView.contentOffset
            offset.y += self.parent.contentInset.top
            self.parent.offset = offset
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView {
        let webview = WKWebView()
        webview.scrollView.delegate = context.coordinator
        // continue setting up webview content
        return webview
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        if uiView.scrollView.contentInset != self.contentInset {
            uiView.scrollView.contentInset = self.contentInset
        }
    }

}

ContentView. Примечание: я использовал 50в качестве константы вместо вычисления размера. Однако можно получить фактический размер, используя GeometryReader.

struct ContentView: View {
    @State var offset: CGPoint = .zero
    var body: some View {
        NavigationView {
            WebView(offset: self.$offset, contentInset: UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0))
            .overlay(
                Text("Hello World!")
                    .frame(height: 50)
                    .offset(y: -self.offset.y)
                , alignment: .topLeading)
                .edgesIgnoringSafeArea(.all)
        }
        .navigationBarItems(leading: Text("Item"))
            .navigationBarTitle("", displayMode: .inline)
    }
}

Related questions

MORE COOL STUFF

Яна Дуггар: все, что она говорила о любви и ее 5-летнем окне, чтобы найти «того самого»

Яна Дуггар: все, что она говорила о любви и ее 5-летнем окне, чтобы найти «того самого»

Яна Дуггар открыто говорила о своих поисках любви. Вот все, что она сказала на эту тему и о своем пятилетнем окне для замужества.

Сэм Хьюэн точно знает, что он возьмет из съемочной площадки «Чужестранки»: «Я чувствую себя Джейми, когда надеваю их»

Сэм Хьюэн точно знает, что он возьмет из съемочной площадки «Чужестранки»: «Я чувствую себя Джейми, когда надеваю их»

Звезда «Чужестранки» Сэм Хьюэн недавно рассказал, что он возьмет со съемочной площадки, чтобы вспомнить Джейми Фрейзера, роль, которая сделала его звездой.

Ранняя песня Beatles, которая вошла в число «самых захватывающих выступлений» группы, по мнению инсайдера Fab Four

Ранняя песня Beatles, которая вошла в число «самых захватывающих выступлений» группы, по мнению инсайдера Fab Four

«She Loves You» была написана за час, записана за день и стала песней The Beatles с одним из лучших исполнений в их карьере.

Долли Партон помогла своей «инвалидной» бабушке, когда ни один из других внуков не стал бы — она тоже разыгрывала ее

Долли Партон помогла своей «инвалидной» бабушке, когда ни один из других внуков не стал бы — она тоже разыгрывала ее

У Долли Партон и ее бабушки Бесси были особые отношения. Бабушка Партон была очень больна, но это не мешало Долли разыгрывать ее.

Какая древесина самая твёрдая в мире?

Какая древесина самая твёрдая в мире?

Вы можете подумать, что дуб или гикори — прочные породы дерева, но когда речь идет о самой твердой древесине в мире, они даже близко не стоят.

10 самых страшных морских существ, скрывающихся в глубинах океана

10 самых страшных морских существ, скрывающихся в глубинах океана

Океан полон красоты, но он также скрывает одних из самых страшных морских существ на планете. Многие из этих животных скрываются глубоко под поверхностью океана, в тёмном, полном давления мире морских глубин.

10 лучших чар для мечей в Minecraft

10 лучших чар для мечей в Minecraft

Если вы сражаетесь с враждебными мобами или готовитесь к PvP-боям, знание лучших чар для мечей в Minecraft может дать вам серьёзное преимущество. Зачарование мечей позволяет наносить больше урона, увеличивать количество выпадающих мобов и продлевать срок службы меча.

13 социалистических стран, которые сильно отличаются друг от друга

13 социалистических стран, которые сильно отличаются друг от друга

Когда говорят о социалистических странах, часто представляют себе полный государственный контроль и отсутствие частной собственности. Но на практике социалистические экономики сильно различаются.

Резюме «Медведя»: Маркус — самый добрый, мягкий и искренний человек в Чикаго?

Резюме «Медведя»: Маркус — самый добрый, мягкий и искренний человек в Чикаго?

В «Детях» появится громкая камео и несколько разрушительных новостей

За 9800 долларов вы бы упаковали их в эту семиместную Toyota RAV4 2008 года выпуска?

За 9800 долларов вы бы упаковали их в эту семиместную Toyota RAV4 2008 года выпуска?

Утверждается, что этот RAV4 находится в отличном состоянии и готов к игре в музыкальные стулья.

Фургон доставки Amazon загорелся в результате огненного взрыва во время летней жары в Хьюстоне

Фургон доставки Amazon загорелся в результате огненного взрыва во время летней жары в Хьюстоне

На кадрах, снятых с дрона, видно, как пожарные изо всех сил пытаются потушить пламя.

«Шоу Черной Пантеры» от Marvel станет самым важным анимационным шоу за всю историю

«Шоу Черной Пантеры» от Marvel станет самым важным анимационным шоу за всю историю

«Глаза Ваканды» напрямую связаны с MCU, а также обновления о «Людях Икс '97», «Что, если...», «Сорвиголова» и многом другом.

История знакомств Авы Гарднер: взгляд назад на браки и романы голливудской иконы

История знакомств Авы Гарднер: взгляд назад на браки и романы голливудской иконы

Ава Гарднер была замужем за Микки Руни и Фрэнком Синтрой, и встречалась с несколькими другими голливудскими звездами. Вот взгляд назад на историю знакомств Авы Гарднер.

Кто жена Джона Клиза? Все о Дженнифер Уэйд

Кто жена Джона Клиза? Все о Дженнифер Уэйд

Джон Клиз женился на Дженнифер Уэйд в 2012 году. Вот все, что нужно знать о жене Джона Клиза, Дженнифер Уэйд.

Кто муж Эллисон Феликс? Все о Кеннете Фергюсоне

Кто муж Эллисон Феликс? Все о Кеннете Фергюсоне

Олимпийская чемпионка Эллисон Феликс вышла замуж за своего мужа Кеннета Фергюсона в 2018 году. Вот все, что нужно знать о муже Эллисон Феликс, Кеннете Фергюсоне.

Кто муж Мены Сувари? Все о Майкле Хоупе

Кто муж Мены Сувари? Все о Майкле Хоупе

Мена Сувари замужем за своим мужем Майклом Хоупом с 2018 года. Вот все, что нужно знать о муже Мены Сувари.

местоимения очень страшные

Это поражает меня Внезапно, как это часто бывает, Это снова и снова на полпути <Нет, не то, что в Тихом океане, ты темно-бордовый, то, что на карнавале> Каждый громкий заголовок…..

3 проверенных способа улучшить свои навыки письма

Преимущества письма и стратегии, которые помогут вам в этом

3 проверенных способа улучшить свои навыки письма

В 2022 году, с выпуском GPT-3, навыки письма, кажется, стали менее важными. С помощью ИИ люди с плохим письмом также могут генерировать качественный персонал.

Медленная эрозия: раскрытие того, как люди угасают в своей карьере

Медленная эрозия: раскрытие того, как люди угасают в своей карьере

В современном быстро меняющемся и конкурентном мире карьера играет важную роль в личностном росте, финансовой стабильности и общей удовлетворенности жизнью. Однако многие люди оказываются в безжалостном цикле застоя и неудовлетворенности, постепенно угасая в своей профессиональной жизни.

Что делает подкаст влиятельным?

Что делает подкаст влиятельным?

На прошлой неделе я заметил пресс-релиз, разосланный через PressGazette (новостной веб-сайт британских СМИ). В статье сообщалось, что Acast, скандинавская компания по размещению и рекламе подкастов, возглавит консорциум «вероятно, самых влиятельных» издателей подкастинга.

Language