Skip to content

Commit 28efb86

Browse files
committed
Fix split views on Catalyst
Prevent resizeHandler() from being called twice in one pass
1 parent 78f5f75 commit 28efb86

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

.github/workflows/build-test-and-docs.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,7 @@ jobs:
173173
buildtarget RandomNumberGeneratorExample
174174
buildtarget WebViewExample
175175
buildtarget AdvancedCustomizationExample
176-
# TODO test whether this works on Catalyst
177-
# buildtarget SplitExample
176+
buildtarget SplitExample
178177
179178
windows:
180179
runs-on: windows-latest

Examples/Bundler.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ identifier = 'dev.swiftcrossui.SplitExample'
3535
product = 'SplitExample'
3636
version = '0.1.0'
3737

38+
[[apps.SplitExample.overlays]]
39+
condition = "platform(macCatalyst)"
40+
interface_idiom = "mac"
41+
3842
[apps.SpreadsheetExample]
3943
identifier = 'dev.swiftcrossui.SpreadsheetExample'
4044
product = 'SpreadsheetExample'

Sources/UIKitBackend/UIKitBackend+SplitView.swift

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,71 @@
11
import UIKit
22

3-
#if os(iOS)
3+
#if os(iOS) || targetEnvironment(macCatalyst)
44
final class SplitWidget: WrapperControllerWidget<UISplitViewController>,
55
UISplitViewControllerDelegate
66
{
7-
var resizeHandler: (() -> Void)?
8-
private let sidebarContainer: ContainerWidget
9-
private let mainContainer: ContainerWidget
7+
private final class ColumnView: UIView {
8+
unowned var splitWidget: SplitWidget!
9+
10+
@available(*, unavailable)
11+
required init?(coder: NSCoder) {
12+
fatalError("init(coder:) is not used for this view")
13+
}
14+
15+
init() {
16+
super.init(frame: .zero)
17+
}
18+
19+
override func layoutSubviews() {
20+
super.layoutSubviews()
21+
if !splitWidget.hasCalledResizeHandler {
22+
splitWidget.resizeHandler?()
23+
splitWidget.hasCalledResizeHandler = true
24+
}
25+
}
26+
}
27+
28+
private final class ColumnWidget: ContainerWidget {
29+
let columnView = ColumnView()
30+
31+
override func loadView() {
32+
view = columnView
33+
}
34+
}
35+
36+
var resizeHandler: (() -> Void)? {
37+
didSet {
38+
hasCalledResizeHandler = false
39+
}
40+
}
41+
42+
// This is just a flag so that we don't call resizeHandler twice in one pass through the run loop.
43+
var hasCalledResizeHandler = false {
44+
willSet {
45+
if newValue {
46+
DispatchQueue.main.async { [weak self] in
47+
self?.hasCalledResizeHandler = false
48+
}
49+
}
50+
}
51+
}
52+
53+
private let sidebarContainer: ColumnWidget
54+
private let mainContainer: ColumnWidget
1055

1156
init(sidebarWidget: some WidgetProtocol, mainWidget: some WidgetProtocol) {
1257
// UISplitViewController requires its children to be controllers, not views
13-
sidebarContainer = ContainerWidget(child: sidebarWidget)
14-
mainContainer = ContainerWidget(child: mainWidget)
58+
sidebarContainer = ColumnWidget(child: sidebarWidget)
59+
mainContainer = ColumnWidget(child: mainWidget)
1560

1661
super.init(child: UISplitViewController())
1762

63+
sidebarContainer.parentWidget = self
64+
mainContainer.parentWidget = self
65+
childWidgets = [sidebarContainer, mainContainer]
66+
sidebarContainer.columnView.splitWidget = self
67+
mainContainer.columnView.splitWidget = self
68+
1869
child.delegate = self
1970

2071
child.preferredDisplayMode = .oneBesideSecondary
@@ -45,11 +96,6 @@ import UIKit
4596

4697
super.viewDidLoad()
4798
}
48-
49-
override func viewDidLayoutSubviews() {
50-
super.viewDidLayoutSubviews()
51-
resizeHandler?()
52-
}
5399
}
54100

55101
extension UIKitBackend {

0 commit comments

Comments
 (0)