Skip to content

Commit b36c7b8

Browse files
committed
SwiftUI example for dynamic table view
1 parent b07dc82 commit b36c7b8

File tree

3 files changed

+144
-9
lines changed

3 files changed

+144
-9
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//
2+
// DynamicViewController.swift
3+
// Example-iOS
4+
//
5+
// Created by Ben on 13/08/2022.
6+
// Copyright © 2022 bcylin.
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
//
26+
27+
import SwiftUI
28+
29+
@available(iOS 13.0, *)
30+
final class DynamicViewController: UIHostingController<DynamicTableView> {
31+
32+
init() {
33+
super.init(rootView: DynamicTableView())
34+
title = "Dynamic"
35+
}
36+
37+
required dynamic init?(coder aDecoder: NSCoder) {
38+
fatalError("init(coder:) has not been implemented")
39+
}
40+
}
41+
42+
// MARK: - ViewModel
43+
44+
@available(iOS 13.0, *)
45+
private final class ViewModel: ObservableObject {
46+
@Published var items: [Item] = []
47+
48+
struct Item: Hashable, Identifiable {
49+
let id = UUID()
50+
let title: String
51+
let number: Int
52+
}
53+
54+
func addItem() {
55+
let newItem = Item(title: "UITableViewCell", number: items.count + 1)
56+
items.append(newItem)
57+
}
58+
}
59+
60+
// MARK: - View
61+
62+
@available(iOS 13.0, *)
63+
struct DynamicTableView: View {
64+
@ObservedObject private var viewModel = ViewModel()
65+
@State private var editMode: EditMode = .inactive
66+
67+
var body: some View {
68+
List {
69+
Section(header: Text("SwiftUI Example")) {
70+
addButton
71+
list(of: viewModel.items)
72+
}
73+
}
74+
.withEditButton()
75+
.environment(\.editMode, $editMode)
76+
}
77+
78+
private var addButton: some View {
79+
Button {
80+
withAnimation { viewModel.addItem() }
81+
} label: {
82+
Text("Add")
83+
.frame(maxWidth: .infinity)
84+
.foregroundColor(editMode == .active ? .gray : .blue)
85+
}
86+
}
87+
88+
private func list(of items: [ViewModel.Item]) -> some View {
89+
ForEach(Array(items.enumerated()), id: \.element) { _, item in
90+
HStack {
91+
Text(item.title)
92+
Spacer()
93+
Text("\(item.number)")
94+
}
95+
}
96+
.onDelete { indexSet in
97+
viewModel.items.remove(atOffsets: indexSet)
98+
}
99+
.onMove { indexSet, newOffset in
100+
viewModel.items.move(fromOffsets: indexSet, toOffset: newOffset)
101+
}
102+
}
103+
}
104+
105+
@available(iOS 13.0, *)
106+
private extension View {
107+
@ViewBuilder
108+
func withEditButton() -> some View {
109+
if #available(iOS 14.0, *) {
110+
self.toolbar { EditButton() }
111+
} else {
112+
self
113+
}
114+
}
115+
}
116+
117+
@available(iOS 13.0, *)
118+
struct TableView_Previews: PreviewProvider {
119+
static var previews: some View {
120+
DynamicTableView()
121+
}
122+
}

Example-iOS/ViewControllers/RootViewController.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,16 @@ internal final class RootViewController: QuickTableViewController {
6969
NavigationRow(text: "UILabel customization", detailText: .none, action: { [weak self] _ in
7070
self?.navigationController?.pushViewController(AppearanceViewController(), animated: true)
7171
})
72-
]),
72+
])
73+
] + swiftUIExamples()
74+
}
75+
76+
func swiftUIExamples() -> [Section] {
77+
guard #available(iOS 13, *) else {
78+
return []
79+
}
7380

81+
return [
7482
Section(title: "Dynamic", rows: [
7583
NavigationRow(text: "Dynamic Rows", detailText: .none, action: { [weak self] _ in
7684
self?.navigationController?.pushViewController(DynamicViewController(), animated: true)

QuickTableViewController.xcodeproj/project.pbxproj

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
136DD300216A367B00F554F0 /* ExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136DD2FF216A367B00F554F0 /* ExampleUITests.swift */; };
1111
136DD307216A36FA00F554F0 /* QuickTableViewController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54A24262088816D00EEBA26 /* QuickTableViewController.framework */; };
1212
136DD308216A36FA00F554F0 /* QuickTableViewController.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B54A24262088816D00EEBA26 /* QuickTableViewController.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
13-
3E27069B23FC4D14003516B8 /* DynamicTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6B15A5323F73E48001DB252 /* DynamicTableView.swift */; };
1413
3E45597A21DA81B100FC0C76 /* DetailText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E45597921DA81B100FC0C76 /* DetailText.swift */; };
1514
3E45597F21DA8B5F00FC0C76 /* DetailTextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E45597D21DA8B3400FC0C76 /* DetailTextTests.swift */; };
1615
3E45598021DA8B6000FC0C76 /* DetailTextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E45597D21DA8B3400FC0C76 /* DetailTextTests.swift */; };
@@ -82,6 +81,7 @@
8281
B5C9175320B1831800C7999C /* QuickTableViewDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52677721FF7F08D00DC1362 /* QuickTableViewDelegateTests.swift */; };
8382
B5C9175420B1831800C7999C /* CustomTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B526776F1FF7EA5A00DC1362 /* CustomTypes.swift */; };
8483
B5C9175520B18A5C00C7999C /* QuickTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B5334F181B8CC5BD00C64A6D /* QuickTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
84+
B5CE707628A8282F001DE6FE /* DynamicViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CE707528A8282F001DE6FE /* DynamicViewController.swift */; };
8585
B5DB7D271C4B7F74007B84D2 /* IconTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DB7D251C4B7F0E007B84D2 /* IconTests.swift */; };
8686
B5DB7D2D1C4B8294007B84D2 /* NavigationRowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DB7D2C1C4B8294007B84D2 /* NavigationRowTests.swift */; };
8787
B5DB7D2F1C4B95D3007B84D2 /* SwitchRowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DB7D2E1C4B95D3007B84D2 /* SwitchRowTests.swift */; };
@@ -100,7 +100,6 @@
100100
B5F0FFEA1E9CC6F9007BF1C9 /* SwitchRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F0FFE91E9CC6F9007BF1C9 /* SwitchRow.swift */; };
101101
B5F0FFEC1E9CC72D007BF1C9 /* TapActionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F0FFEB1E9CC72D007BF1C9 /* TapActionRow.swift */; };
102102
B5F0FFEE1E9CC73D007BF1C9 /* Subtitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F0FFED1E9CC73D007BF1C9 /* Subtitle.swift */; };
103-
F6B15A5623F74268001DB252 /* DynamicTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6B15A5523F74268001DB252 /* DynamicTableViewController.swift */; };
104103
/* End PBXBuildFile section */
105104

106105
/* Begin PBXContainerItemProxy section */
@@ -225,6 +224,7 @@
225224
B5A37EB52020937A009C075F /* OptionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OptionCell.xib; sourceTree = "<group>"; };
226225
B5A67A1120205F5C0075E0C8 /* CustomizationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizationViewController.swift; sourceTree = "<group>"; };
227226
B5A67A13202069440075E0C8 /* RootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = "<group>"; };
227+
B5CE707528A8282F001DE6FE /* DynamicViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicViewController.swift; sourceTree = "<group>"; };
228228
B5DB7D251C4B7F0E007B84D2 /* IconTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IconTests.swift; sourceTree = "<group>"; };
229229
B5DB7D2C1C4B8294007B84D2 /* NavigationRowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationRowTests.swift; sourceTree = "<group>"; };
230230
B5DB7D2E1C4B95D3007B84D2 /* SwitchRowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchRowTests.swift; sourceTree = "<group>"; };
@@ -245,8 +245,6 @@
245245
B5F0FFE91E9CC6F9007BF1C9 /* SwitchRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchRow.swift; sourceTree = "<group>"; };
246246
B5F0FFEB1E9CC72D007BF1C9 /* TapActionRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TapActionRow.swift; sourceTree = "<group>"; };
247247
B5F0FFED1E9CC73D007BF1C9 /* Subtitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Subtitle.swift; sourceTree = "<group>"; };
248-
F6B15A5323F73E48001DB252 /* DynamicTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicTableView.swift; sourceTree = "<group>"; };
249-
F6B15A5523F74268001DB252 /* DynamicTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicTableViewController.swift; sourceTree = "<group>"; };
250248
/* End PBXFileReference section */
251249

252250
/* Begin PBXFrameworksBuildPhase section */
@@ -416,6 +414,7 @@
416414
B51F21A31F417037009BC2C9 /* Example-iOS */ = {
417415
isa = PBXGroup;
418416
children = (
417+
B5CE707728A8DB94001DE6FE /* SwiftUI */,
419418
B5A37EB7202093A3009C075F /* UINibs */,
420419
B5A37EB8202093C3009C075F /* ViewControllers */,
421420
B51F21A41F417037009BC2C9 /* AppDelegate.swift */,
@@ -545,14 +544,21 @@
545544
children = (
546545
B5A37EAD20208EF7009C075F /* AppearanceViewController.swift */,
547546
B5A67A1120205F5C0075E0C8 /* CustomizationViewController.swift */,
548-
F6B15A5323F73E48001DB252 /* DynamicTableView.swift */,
549-
F6B15A5523F74268001DB252 /* DynamicTableViewController.swift */,
550547
B51F21A61F417037009BC2C9 /* ExampleViewController.swift */,
551548
B5A67A13202069440075E0C8 /* RootViewController.swift */,
552549
);
553550
path = ViewControllers;
554551
sourceTree = "<group>";
555552
};
553+
B5CE707728A8DB94001DE6FE /* SwiftUI */ = {
554+
isa = PBXGroup;
555+
children = (
556+
B5CE707528A8282F001DE6FE /* DynamicViewController.swift */,
557+
);
558+
indentWidth = 4;
559+
path = SwiftUI;
560+
sourceTree = "<group>";
561+
};
556562
/* End PBXGroup section */
557563

558564
/* Begin PBXHeadersBuildPhase section */
@@ -991,8 +997,7 @@
991997
B51F21A51F417037009BC2C9 /* AppDelegate.swift in Sources */,
992998
B5A37EAE20208EF7009C075F /* AppearanceViewController.swift in Sources */,
993999
B5A67A1220205F5C0075E0C8 /* CustomizationViewController.swift in Sources */,
994-
3E27069B23FC4D14003516B8 /* DynamicTableView.swift in Sources */,
995-
F6B15A5623F74268001DB252 /* DynamicTableViewController.swift in Sources */,
1000+
B5CE707628A8282F001DE6FE /* DynamicViewController.swift in Sources */,
9961001
B51F21A71F417037009BC2C9 /* ExampleViewController.swift in Sources */,
9971002
B5A67A14202069440075E0C8 /* RootViewController.swift in Sources */,
9981003
);

0 commit comments

Comments
 (0)