Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions ios/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,60 @@ import UIKit

/**
Helper used to render UIView inside of SwiftUI.
Uses UIViewControllerRepresentable to re-inject safe area insets
that SwiftUI's .ignoresSafeArea() strips from child UIKit views.
*/
struct RepresentableView: UIViewRepresentable {
struct RepresentableView: UIViewControllerRepresentable {
var view: UIView

// Adding a wrapper UIView to avoid SwiftUI directly managing React Native views.
// This fixes issues with incorrect layout rendering.
func makeUIView(context: Context) -> UIView {
let wrapper = UIView()
wrapper.addSubview(view)
return wrapper
func makeUIViewController(context: Context) -> PageChildViewController {
let viewController = PageChildViewController()
viewController.wrappedView = view
return viewController
}

func updateUIView(_ uiView: UIView, context: Context) {}
func updateUIViewController(_ uiViewController: PageChildViewController, context: Context) {}
}

class PageChildViewController: UIViewController {
var wrappedView: UIView?

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
if let wrappedView {
view.addSubview(wrappedView)
}
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
propagateHostingSafeArea()
}

/// Traverses up to the _UIHostingView and re-applies its bottom safe area
/// as additionalSafeAreaInsets on this child VC, since .ignoresSafeArea()
/// causes UIKit to report safeAreaInsets = .zero for embedded views.
private func propagateHostingSafeArea() {
var current: UIView? = view.superview
while let v = current {
if String(describing: type(of: v)).contains("_UIHostingView") {
let hosting = v.safeAreaInsets
let delta = UIEdgeInsets(
top: hosting.top, left: hosting.left,
bottom: hosting.bottom, right: hosting.right
)
if abs(additionalSafeAreaInsets.top - delta.top) > 0.5
|| abs(additionalSafeAreaInsets.left - delta.left) > 0.5
|| abs(additionalSafeAreaInsets.bottom - delta.bottom) > 0.5
|| abs(additionalSafeAreaInsets.right - delta.right) > 0.5 {
additionalSafeAreaInsets = delta
}
return
}
current = v.superview
}
}
}

extension Collection {
Expand Down
1 change: 1 addition & 0 deletions ios/PagerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct PagerView: View {
.id(props.children.count)
.background(.clear)
.tabViewStyle(.page(indexDisplayMode: .never))
.ignoresSafeArea()
.environment(\.layoutDirection, props.layoutDirection.converted)
.introspect(.tabView(style: .page), on: .iOS(.v14...)) { collectionView in
self.collectionView = collectionView
Expand Down
3 changes: 1 addition & 2 deletions ios/PagerViewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ import UIKit
}

self.hostingController = UIHostingController(
rootView: PagerView(props: props, delegate: delegate),
ignoreSafeArea: true
rootView: PagerView(props: props, delegate: delegate)
)
if let hostingController, let parentViewController = reactViewController() {
parentViewController.addChild(hostingController)
Expand Down