13.3 C
Canberra
Wednesday, February 18, 2026

Inexplicable white background under SwiftUI Webview


I am engaged on a pair of Swift tasks, and one in all them, operating on an iPad, refuses to cooperate with this webview. The picture under reveals the whitespace under the editor. This solely seems when the consumer scrolls right down to the underside of the editor’s content material. For context, the editor locks the physique peak to 100vh when in panorama mode so this could show an editor in a side-by-side scrollable container, and this whitespace does not seem when the iPad is in portrait mode with the editor hidden.

Inexplicable white background under SwiftUI Webview

Additionally, I’ve enabled vim mode within the editor, and this appears to happen extra regularly, virtually completely when the editor is in vim mode and the consumer jumps to the underside of the word’s content material.

That is my webview:

struct MarkdownTabView: View {
  @Binding var editingNote: NoteModel?
  @Binding var fullScreenCover: MainFullScreenCover?
  var onNavigateToNote: (NoteModel) -> Void = { _ in }
  @AppStorage(AppStorageKeys.editorThemeDark.rawValue) personal
    var editorThemeDark: CodeSyntaxTheme = .dracula
  @AppStorage(AppStorageKeys.editorThemeLight.rawValue) personal
    var editorThemeLight: CodeSyntaxTheme = .githubLight
  @AppStorage(AppStorageKeys.theme.rawValue) personal var theme: WebViewTheme =
    .fluster
  @AppStorage(AppStorageKeys.editorKeymap.rawValue) personal var editorKeymap: EditorKeymap = .base
  @AppStorage(AppStorageKeys.hasLaunchedPreviously.rawValue) personal
    var hasPreviouslyLaunched: Bool = false
  @Atmosphere(ThemeManager.self) personal var themeManager: ThemeManager
  var editorContainer: MdxEditorWebviewContainer
  init(
    editingNote: Binding<NoteModel?>, editorContainer: MdxEditorWebviewContainer,
    onNavigateToNote: ((NoteModel) -> Void)?,
    fullScreenCover: Binding<MainFullScreenCover?>
  ) {
    self._editingNote = editingNote
    self._fullScreenCover = fullScreenCover
    self.editorContainer = editorContainer
    if onNavigateToNote != nil {
      self.onNavigateToNote = onNavigateToNote!
    }
  }
  var physique: some View {
    if let editingNoteBinding = Binding($editingNote) {
      NavigationStack {
        MdxEditorWebview(
          url:
            Bundle.most important.url(
              forResource: "index",
              withExtension: "html",
              subdirectory: "splitview_mdx_editor"
            )!,
          theme: $theme,
          editorThemeDark: $editorThemeDark,
          editorThemeLight: $editorThemeLight,
          editingNote: editingNoteBinding,
          editorKeymap: $editorKeymap,
          container: editorContainer,
          onNavigateToNote: onNavigateToNote,
          fullScreenCover: $fullScreenCover
        )
        .body(maxWidth: .infinity, maxHeight: .infinity)
        //                .body(width: geo.dimension.width, peak: geo.dimension.peak, alignment: .topLeading)
        // TODO: Take away this. That is only for simple improvement.
        .onAppear {
          if let parsedMdx = editingNote?.markdown
            .preParsedBody
          {
            editorContainer.setParsedEditorContentString(
              content material: parsedMdx
            )
          }
          UIScrollView.look().bounces = false
          UIScrollView.look().isScrollEnabled =
            false
        }
        .onDisappear {
          UIScrollView.look().bounces = true
          UIScrollView.look().isScrollEnabled = true
        }
      }
    } else {
      if hasPreviouslyLaunched {
        SelectNoteToContinueView()
      } else {
        ProgressView()
          .progressViewStyle(.round)
          .scaleEffect(1.5)
          .tint(themeManager.theme.main)
      }
    }
  }
}

And the MdxEditorWebview:

  @MainActor
  public struct MdxEditorWebviewInternal: UIViewRepresentable {
    @State personal var webView: WKWebView = WKWebView(
      body: .zero,
      configuration: getConfig()
    )
    @State personal var didSetInitialContent = false
    @State var haveSetInitialContent: Bool = false
    @Atmosphere(.openURL) var openURL
    @Atmosphere(.modelContext) var modelContext
    @Atmosphere(.colorScheme) var colorScheme
    @Atmosphere(.createDataHandler) var dataHandler
    @AppStorage(AppStorageKeys.webviewFontSize.rawValue) personal
      var webviewFontSize: WebviewFontSize = .base
    let url: URL
    @Binding var present: Bool
    @Binding var theme: WebViewTheme
    @Binding var editorThemeDark: CodeSyntaxTheme
    @Binding var editorThemeLight: CodeSyntaxTheme
    @Binding var editingNote: NoteModel
    @Binding var editorKeymap: EditorKeymap
    @Binding var fullScreenCover: MainFullScreenCover?
    var onNavigateToNote: (NoteModel) -> Void

    let container: MdxEditorWebviewContainer

    public init(
      url: URL,
      theme: Binding<WebViewTheme>,
      editorThemeDark: Binding<CodeSyntaxTheme>,
      editorThemeLight: Binding<CodeSyntaxTheme>,
      editingNote: Binding<NoteModel>,
      editorKeymap: Binding<EditorKeymap>,
      container: MdxEditorWebviewContainer,
      present: Binding<Bool>,
      onNavigateToNote: @escaping (NoteModel) -> Void,
      fullScreenCover: Binding<MainFullScreenCover?>
    ) {
      self.url = url
      self._theme = theme
      self._editorThemeDark = editorThemeDark
      self._editorThemeLight = editorThemeLight
      self._editingNote = editingNote
      self._editorKeymap = editorKeymap
      self._fullScreenCover = fullScreenCover
      self.container = container
      self._show = present
      self.onNavigateToNote = onNavigateToNote
    }

    public func makeUIView(context: Context) -> WKWebView {
      let webView = container.webView
      webView.isHidden = true

      webView.navigationDelegate = context.coordinator
      let editorContentControllers = [
        SplitviewEditorWebviewActions.setWebviewLoaded.rawValue,
        SplitviewEditorWebviewActions.onEditorChange.rawValue,
        SplitviewEditorWebviewActions.requestSplitviewEditorData.rawValue,
        SplitviewEditorWebviewActions.requestParsedMdxContent.rawValue,
        SplitviewEditorWebviewActions.onTagClick.rawValue,
        MdxPreviewWebviewActions.viewNoteByUserDefinedId.rawValue,
        MdxPreviewWebviewActions.requestNoteData.rawValue
      ]
      if colorScheme == .darkish {
        webView.evaluateJavaScript(
          """
          doc.physique.classList.add("darkish"); null;
          """
        )
      }
      for controllerName in editorContentControllers {
        addUserContentController(
          controller: webView.configuration.userContentController,
          coordinator: context.coordinator,
          identify: controllerName
        )
      }

      // Loading the web page solely as soon as
      webView.loadFileURL(url, allowingReadAccessTo: url)

      if colorScheme == .darkish {
        webView.evaluateJavaScript(
          """
          doc.physique.classList.add("darkish"); null;
          """
        )
      }

      return webView
    }

    public func updateUIView(_ uiView: WKWebView, context: Context) {
      uiView.isHidden = !present
      //        uiView.scrollView.contentInset = .zero
      //        uiView.scrollView.scrollIndicatorInsets = .zero
    }
    public func makeCoordinator() -> Coordinator {
      Coordinator(self)
    }
    public func setInitialProperties() {
      container.setInitialProperties(
        editingNote: editingNote,
        codeEditorTheme: colorScheme == .darkish
          ? editorThemeDark : editorThemeLight,
        editorKeymap: editorKeymap,
        theme: theme,
        fontSize: webviewFontSize,
        editorThemeDark: editorThemeDark,
        editorThemeLight: editorThemeLight,
        darkMode: colorScheme == .darkish,
        modelContext: modelContext
      )
    }
    public func setInitialContent() {
      let s = editingNote.markdown.physique.toQuotedJavascriptString() ?? "''"
      container.runJavascript(
        """
        window.localStorage.setItem("(SplitviewEditorWebviewLocalStorageKeys.initialValue.rawValue)", (s))
        window.setEditorContent((s))
        """
      )
    }
    public func handleViewNoteByUserDefinedId(id: String) {
      print("Right here...")
      let fetchDescriptor = FetchDescriptor<NoteModel>(
        predicate: #Predicate { word in
          word.frontMatter.userDefinedId == id
        })
      if let notes = strive? self.modelContext.fetch(fetchDescriptor) {
        if !notes.isEmpty {
          let word = notes.first
          self.editingNote = word!
          self.onNavigateToNote(word!)
        }
      }
    }
    public func handleTagClick(tagBody: String) {
      let fetchDescriptor = FetchDescriptor<TagModel>(
        predicate: #Predicate<TagModel> { t in
          t.worth == tagBody
        })
      if let tags = strive? modelContext.fetch(fetchDescriptor) {
        if !tags.isEmpty {
          fullScreenCover = .tagSearch(tag: tags.first!)
        }
      }
    }
  }

  public struct MdxEditorWebview: View {
    @State personal var present: Bool = false
    @State personal var showEditNoteTaggables: Bool = false
    @Atmosphere(ThemeManager.self) personal var themeManager: ThemeManager
    let url: URL
    @Binding var theme: WebViewTheme
    @Binding var editorThemeDark: CodeSyntaxTheme
    @Binding var editorThemeLight: CodeSyntaxTheme
    @Binding var editingNote: NoteModel
    @Binding var editorKeymap: EditorKeymap
    @Binding var fullScreenCover: MainFullScreenCover?
    var onNavigateToNote: (NoteModel) -> Void
    let container: MdxEditorWebviewContainer
    public init(
      url: URL,
      theme: Binding<WebViewTheme>,
      editorThemeDark: Binding<CodeSyntaxTheme>,
      editorThemeLight: Binding<CodeSyntaxTheme>,
      editingNote: Binding<NoteModel>,
      editorKeymap: Binding<EditorKeymap>,
      container: MdxEditorWebviewContainer,
      onNavigateToNote: @escaping (NoteModel) -> Void,
      fullScreenCover: Binding<MainFullScreenCover?>?
    ) {
      self.url = url
      self._theme = theme
      self._editorThemeDark = editorThemeDark
      self._editorThemeLight = editorThemeLight
      self._editingNote = editingNote
      self._editorKeymap = editorKeymap
      self.container = container
      self.onNavigateToNote = onNavigateToNote
      if let fs = fullScreenCover {
        self._fullScreenCover = fs
      } else {
        self._fullScreenCover = .fixed(nil)
      }
      self.onNavigateToNote = onNavigateToNote
    }

    public var physique: some View {
      ZStack(alignment: present ? .bottomTrailing : .heart) {
        MdxEditorWebviewInternal(
          url: url,
          theme: $theme,
          editorThemeDark: $editorThemeDark,
          editorThemeLight: $editorThemeLight,
          editingNote: $editingNote,
          editorKeymap: $editorKeymap,
          container: container,
          present: $present,
          onNavigateToNote: onNavigateToNote,
          fullScreenCover: $fullScreenCover,
        )
        .disableAnimations()
        .body(
          alignment: .backside
        )
        .scrollDisabled(true)
        if !present {
          ProgressView()
            .progressViewStyle(.round)
            .scaleEffect(1.5)
            .tint(themeManager.theme.main)
        } else {
          FloatingButtonView(
            buttons: [
              FloatingButtonItem(
                id: "addTaggable",
                systemImage: "tag.fill",
                action: {
                  withAnimation {
                    showEditNoteTaggables.toggle()
                  }
                }
              ),
              FloatingButtonItem(
                id: "toggleBookmarked",
                systemImage: editingNote.bookmarked ? "bookmark.fill" : "bookmark",
                action: {
                  editingNote.bookmarked.toggle()
                }
              )
            ]
          )
          .padding()
        }
      }
      .fullScreenCover(
        isPresented: $showEditNoteTaggables,
        content material: {
          EditNoteTaggablesView(
            editingNote: $editingNote,
            open: $showEditNoteTaggables
          )
        },
      )
    }
    
      func onLoad() async {
          
      }
  }
#endif

Thanks upfront for any recommendations. I’ve solely been working with Swift for a pair months so there’s nonetheless loads for me to study.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles