Adding a custom NSScrollView
into SwiftUI
, there is a WKWebview
inside a HStack
which is added to NSScrollView
via NSHostingView
The WKWebview
doesn't go fullscreen properly (doesnt resize and sticks to the leading
edge) when
child.translatesAutoresizingMaskIntoConstraints = false
, if I skip this then the
fullscreen works as normal however the AutoLayout
won't work because of this.
struct ContentView: View {
var body: some View {
VStack {
ScrollViewX {
HStack {
WebViewX()
.frame(width: 300, height: 300)
}
}
.frame(width: 500, height : 500)
}.frame(width: 700, height : 700)
}
}
struct ScrollViewX<Content : View>: NSViewRepresentable {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
func makeNSView(context: Context) -> CustomScrollView {
let view = CustomScrollView(frame: .zero)
let child = NSHostingView(rootView: content)
child.translatesAutoresizingMaskIntoConstraints = false
view.documentView = child
child.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
child.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
return view
}
func updateNSView(_ nsView: CustomScrollView, context: Context) {
}
}
class CustomScrollView: NSScrollView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.drawsBackground = false
self.hasHorizontalScroller = true
self.hasVerticalScroller = false
self.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct WebViewX: NSViewRepresentable {
func makeNSView(context: Context) -> customWebView {
let webView = customWebView(url: nil)
return webView
}
func updateNSView(_ NSView: customWebView, context: Context) {
}
}
class customWebView : WKWebView {
convenience init(url : String?) {
let config = WKWebViewConfiguration()
config.limitsNavigationsToAppBoundDomains = false
config.preferences.isTextInteractionEnabled = true
config.preferences.setValue(true, forKey: "fullScreenEnabled")
config.preferences.javaScriptCanOpenWindowsAutomatically = true
config.defaultWebpagePreferences.allowsContentJavaScript = true
self.init(frame: .zero, configuration : config)
self.allowsBackForwardNavigationGestures = false
self.allowsMagnification = true
self.translatesAutoresizingMaskIntoConstraints = false
let req = URLRequest(url: URL(string: "https://www.youtube.com")!)
self.load(req)
}
convenience required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
CodePudding user response:
Solved it thanks to @Asperi
The issue is due to the frame() on WebViewX()
When you add a NSHostingView() in Appkit the SwiftUI frame modifier disables the view from resizing during fullscreen.
The solution is to change the frame() on willEnterFullscreen and exitFullscreen notifications.
Maybe there are better solutions using Auto-layout
CodePudding user response:
All conditions still not clear, but actually it is horizontal scroller, so height definitely can be constraint, but for content... every view have to have some width defined (or at least have some rule to calculate). Any other hardcodes should be removed.
Thus with below changes all works in full screen as expected automatically (tested with Xcode 13.4 / macOS 12.4)
// in main:
VStack {
ScrollViewX {
HStack {
WebViewX(url: "https://www.apple.com")
.frame(width: 500)
WebViewX(url: "https://www.google.com")
.frame(width: 500)
WebViewX(url: "https://www.stackoverflow.com")
.frame(width: 500)
WebViewX()
.frame(width: 500)
}
}
}
}
// in ScrollViewX:
func makeNSView(context: Context) -> CustomScrollView {
let view = CustomScrollView(frame: .zero)
let child = NSHostingView(rootView: content)
child.translatesAutoresizingMaskIntoConstraints = false
view.documentView = child
child.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
child.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// this one !!
child.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
return view
}