From 8cf0c823ec90bf8f1e62f76c4e96801ba3e3bc23 Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Tue, 4 Jun 2019 16:52:20 -0700 Subject: [PATCH 1/7] make ContentViewController with SwiftUI --- PagingKit.xcodeproj/project.pbxproj | 5 +++++ PagingKit/ContentViewController.swift | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 PagingKit/ContentViewController.swift diff --git a/PagingKit.xcodeproj/project.pbxproj b/PagingKit.xcodeproj/project.pbxproj index 57e8d85..6971977 100644 --- a/PagingKit.xcodeproj/project.pbxproj +++ b/PagingKit.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 2B4F03471F8FAE5D0015FCC8 /* PagingMenuViewCellStub.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B4F03461F8FAE5D0015FCC8 /* PagingMenuViewCellStub.xib */; }; 2B4F03491F8FB9950015FCC8 /* PagingContentViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B4F03481F8FB9950015FCC8 /* PagingContentViewControllerTests.swift */; }; 2B668C5F1F1395BE008A0694 /* PagingMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B668C5E1F1395BE008A0694 /* PagingMenuView.swift */; }; + 2BA286A322A73AD500582ABA /* ContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BA286A222A73AD500582ABA /* ContentViewController.swift */; }; 2BC16A321FFE355F00CB884A /* UnderlineFocusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC16A311FFE355F00CB884A /* UnderlineFocusView.swift */; }; 2BC16A341FFE35AA00CB884A /* PagingKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC16A331FFE35AA00CB884A /* PagingKitProxy.swift */; }; 2BC16A361FFE3B3E00CB884A /* TitleLabelMenuViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC16A351FFE3B3E00CB884A /* TitleLabelMenuViewCell.swift */; }; @@ -41,6 +42,7 @@ 2B4F03461F8FAE5D0015FCC8 /* PagingMenuViewCellStub.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PagingMenuViewCellStub.xib; sourceTree = ""; }; 2B4F03481F8FB9950015FCC8 /* PagingContentViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingContentViewControllerTests.swift; sourceTree = ""; }; 2B668C5E1F1395BE008A0694 /* PagingMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagingMenuView.swift; sourceTree = ""; }; + 2BA286A222A73AD500582ABA /* ContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewController.swift; sourceTree = ""; }; 2BC16A311FFE355F00CB884A /* UnderlineFocusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnderlineFocusView.swift; sourceTree = ""; }; 2BC16A331FFE35AA00CB884A /* PagingKitProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingKitProxy.swift; sourceTree = ""; }; 2BC16A351FFE3B3E00CB884A /* TitleLabelMenuViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLabelMenuViewCell.swift; sourceTree = ""; }; @@ -102,6 +104,7 @@ 2BC16A311FFE355F00CB884A /* UnderlineFocusView.swift */, 2BC16A351FFE3B3E00CB884A /* TitleLabelMenuViewCell.swift */, 2BC16A331FFE35AA00CB884A /* PagingKitProxy.swift */, + 2BA286A222A73AD500582ABA /* ContentViewController.swift */, ); path = PagingKit; sourceTree = ""; @@ -196,6 +199,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -241,6 +245,7 @@ 2B668C5F1F1395BE008A0694 /* PagingMenuView.swift in Sources */, 6EC140D71F09410F0054B514 /* PagingMenuViewController.swift in Sources */, 2B283F051FA8A2BD00DA2FE4 /* Array+NSLayoutConstraint.swift in Sources */, + 2BA286A322A73AD500582ABA /* ContentViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/PagingKit/ContentViewController.swift b/PagingKit/ContentViewController.swift new file mode 100644 index 0000000..7f3437a --- /dev/null +++ b/PagingKit/ContentViewController.swift @@ -0,0 +1,22 @@ +// +// ContentViewController.swift +// PagingKit +// +// Created by Kazuhiro Hayashi on 6/4/31 H. +// Copyright © 2019 Kazuhiro Hayashi. All rights reserved. +// + +import SwiftUI +import UIKit + +struct ContentViewController: UIViewControllerRepresentable { + var controller: [UIViewController] + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingContentViewController { + return PagingContentViewController() + } + + func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { + + } +} From fee3d5bad9a7fbfaea7e487e7305f7b2ef8762ff Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Wed, 5 Jun 2019 22:26:14 -0700 Subject: [PATCH 2/7] add coordinator --- PagingKit/ContentViewController.swift | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/PagingKit/ContentViewController.swift b/PagingKit/ContentViewController.swift index 7f3437a..09f2f5f 100644 --- a/PagingKit/ContentViewController.swift +++ b/PagingKit/ContentViewController.swift @@ -10,13 +10,33 @@ import SwiftUI import UIKit struct ContentViewController: UIViewControllerRepresentable { - var controller: [UIViewController] + func makeCoordinator() -> ContentViewController.Coordinator { + Coordinator(self) + } + + var controllers: [UIViewController] func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingContentViewController { return PagingContentViewController() } func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { + uiViewController.reloadData() + } + + class Coordinator: NSObject, PagingContentViewControllerDataSource { + func numberOfItemsForContentViewController(viewController: PagingContentViewController) -> Int { + return parent.controllers.count + } + + func contentViewController(viewController: PagingContentViewController, viewControllerAt index: Int) -> UIViewController { + parent.controllers[index] + } + + var parent: ContentViewController + init(_ contentViewController: ContentViewController) { + self.parent = contentViewController + } } } From 8f2e16986a682c1bb2b2a6a83f4d864b4c90de2d Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Sat, 22 Jun 2019 17:17:03 +0900 Subject: [PATCH 3/7] Add SwiftUI sample --- PagingKit/ContentViewController.swift | 23 ++++ .../iOS Sample.xcodeproj/project.pbxproj | 21 +++ .../iOS Sample/Base.lproj/Main.storyboard | 123 +++++++++++------- iOS Sample/iOS Sample/SimpleView.swift | 25 ++++ .../SwiftUIViewController.storyboard | 65 +++++++++ .../iOS Sample/SwiftUIViewController.swift | 73 +++++++++++ 6 files changed, 282 insertions(+), 48 deletions(-) create mode 100644 iOS Sample/iOS Sample/SimpleView.swift create mode 100644 iOS Sample/iOS Sample/SwiftUIViewController.storyboard create mode 100644 iOS Sample/iOS Sample/SwiftUIViewController.swift diff --git a/PagingKit/ContentViewController.swift b/PagingKit/ContentViewController.swift index 09f2f5f..bd0fb79 100644 --- a/PagingKit/ContentViewController.swift +++ b/PagingKit/ContentViewController.swift @@ -9,6 +9,29 @@ import SwiftUI import UIKit +@available(iOS 13.0, *) +public struct Menu where Selection : SelectionManager, Content : View { + + /// Creates an instance. + /// + /// - Parameter selection: A selection manager that identifies the selected row(s). + /// + /// - See Also: `View.selectionValue` which gives an identifier to the rows. + /// + /// - Note: On iOS and tvOS, you must explicitly put the `List` into Edit + /// Mode for the selection to apply. + public init(selection: Binding?, content: () -> Content) { + + } + + /// The type of view representing the body of this view. + /// + /// When you create a custom view, Swift infers this type from your + /// implementation of the required `body` property. + public typealias Body = Never +} + + struct ContentViewController: UIViewControllerRepresentable { func makeCoordinator() -> ContentViewController.Coordinator { Coordinator(self) diff --git a/iOS Sample/iOS Sample.xcodeproj/project.pbxproj b/iOS Sample/iOS Sample.xcodeproj/project.pbxproj index 2d37a0e..5c44e07 100644 --- a/iOS Sample/iOS Sample.xcodeproj/project.pbxproj +++ b/iOS Sample/iOS Sample.xcodeproj/project.pbxproj @@ -55,6 +55,9 @@ 2BC7828C2127EFCB009999F6 /* InitializingWithoutStoryboardViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2BC7828B2127EFCB009999F6 /* InitializingWithoutStoryboardViewController.storyboard */; }; 2BE47F081FA41AF40057A786 /* FullscreenViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2BE47F071FA41AF40057A786 /* FullscreenViewController.storyboard */; }; 2BE47F0A1FA41B090057A786 /* FullscreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BE47F091FA41B090057A786 /* FullscreenViewController.swift */; }; + 2BEDEC0422BE1270001B29D9 /* SimpleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BEDEC0322BE1270001B29D9 /* SimpleView.swift */; }; + 2BEDEC0A22BE16D1001B29D9 /* SwiftUIViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2BEDEC0922BE16D1001B29D9 /* SwiftUIViewController.storyboard */; }; + 2BEDEC0C22BE1747001B29D9 /* SwiftUIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BEDEC0B22BE1747001B29D9 /* SwiftUIViewController.swift */; }; 2BFA4AC31F0CEC39001B9BCA /* ModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BFA4AC21F0CEC39001B9BCA /* ModalViewController.swift */; }; 6E98277A1F0A91F400860828 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9827791F0A91F400860828 /* AppDelegate.swift */; }; 6E98277C1F0A91F400860828 /* SimpleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E98277B1F0A91F400860828 /* SimpleViewController.swift */; }; @@ -146,6 +149,9 @@ 2BC7828B2127EFCB009999F6 /* InitializingWithoutStoryboardViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = InitializingWithoutStoryboardViewController.storyboard; sourceTree = ""; }; 2BE47F071FA41AF40057A786 /* FullscreenViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = FullscreenViewController.storyboard; sourceTree = ""; }; 2BE47F091FA41B090057A786 /* FullscreenViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenViewController.swift; sourceTree = ""; }; + 2BEDEC0322BE1270001B29D9 /* SimpleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleView.swift; sourceTree = ""; }; + 2BEDEC0922BE16D1001B29D9 /* SwiftUIViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SwiftUIViewController.storyboard; sourceTree = ""; }; + 2BEDEC0B22BE1747001B29D9 /* SwiftUIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIViewController.swift; sourceTree = ""; }; 2BFA4AC21F0CEC39001B9BCA /* ModalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = ""; }; 6E9827761F0A91F400860828 /* iOS Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Sample.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 6E9827791F0A91F400860828 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -345,6 +351,16 @@ name = Fullscreen; sourceTree = ""; }; + 2BEDEC0122BE1240001B29D9 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + 2BEDEC0322BE1270001B29D9 /* SimpleView.swift */, + 2BEDEC0922BE16D1001B29D9 /* SwiftUIViewController.storyboard */, + 2BEDEC0B22BE1747001B29D9 /* SwiftUIViewController.swift */, + ); + name = SwiftUI; + sourceTree = ""; + }; 6E98276D1F0A91F400860828 = { isa = PBXGroup; children = ( @@ -370,6 +386,7 @@ 6E9827781F0A91F400860828 /* iOS Sample */ = { isa = PBXGroup; children = ( + 2BEDEC0122BE1240001B29D9 /* SwiftUI */, 2B14059F218EBD7200474615 /* NavigationBar */, 2BC782882127ECEE009999F6 /* InitializingWithoutStoryboard */, 2B40528F20425C6C0017F90E /* DynamicWidth */, @@ -514,6 +531,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -560,6 +578,7 @@ 2B4F034C1F9052060015FCC8 /* ContentViewController.storyboard in Resources */, 6E98277F1F0A91F400860828 /* Main.storyboard in Resources */, 2B4541991FA48FFC00A9B253 /* IndicatorFocusMenuView.xib in Resources */, + 2BEDEC0A22BE16D1001B29D9 /* SwiftUIViewController.storyboard in Resources */, 2B4541931FA48E7800A9B253 /* IndicatorViewController.storyboard in Resources */, 2BBB70EC1F92351200320900 /* SimpleViewController.storyboard in Resources */, ); @@ -591,6 +610,7 @@ 2BE47F0A1FA41B090057A786 /* FullscreenViewController.swift in Sources */, 2BFA4AC31F0CEC39001B9BCA /* ModalViewController.swift in Sources */, 2B4541951FA48E8D00A9B253 /* IndicatorViewController.swift in Sources */, + 2BEDEC0C22BE1747001B29D9 /* SwiftUIViewController.swift in Sources */, 2B95EA05203157C70054F23E /* MenuReloadableViewController.swift in Sources */, 2B95EA0A203164BE0054F23E /* AlignmentViewController.swift in Sources */, 2B47E72F1F10957100D67C04 /* OverlayViewController.swift in Sources */, @@ -605,6 +625,7 @@ 2B45419D1FA490BE00A9B253 /* PhotoViewController.swift in Sources */, 2B47F87A1F5BF173001A7D2B /* DynamicSizeViewController.swift in Sources */, 2B7F2E65217EBF1400523F2E /* NavigationBarViewController.swift in Sources */, + 2BEDEC0422BE1270001B29D9 /* SimpleView.swift in Sources */, 2B47E7341F109DE400D67C04 /* OverlayFocusView.swift in Sources */, 2BC1B4181F19F29800829D1A /* TagViewController.swift in Sources */, 2B4F03501F90575B0015FCC8 /* ContentTableViewController.swift in Sources */, diff --git a/iOS Sample/iOS Sample/Base.lproj/Main.storyboard b/iOS Sample/iOS Sample/Base.lproj/Main.storyboard index fd9d4d9..d5b0633 100644 --- a/iOS Sample/iOS Sample/Base.lproj/Main.storyboard +++ b/iOS Sample/iOS Sample/Base.lproj/Main.storyboard @@ -1,11 +1,9 @@ - - - - + + - + @@ -72,7 +70,7 @@ - + @@ -96,14 +94,14 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + @@ -417,6 +436,14 @@ + + + + + + + + diff --git a/iOS Sample/iOS Sample/SimpleView.swift b/iOS Sample/iOS Sample/SimpleView.swift new file mode 100644 index 0000000..87b3b01 --- /dev/null +++ b/iOS Sample/iOS Sample/SimpleView.swift @@ -0,0 +1,25 @@ +// +// SimpleView.swift +// iOS Sample +// +// Created by kahayash on 6/22/1 R. +// Copyright © 2019 Kazuhiro Hayashi. All rights reserved. +// + +import SwiftUI + +@available(iOS 13, *) +struct SimpleView : View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello World!"/*@END_MENU_TOKEN@*/) + } +} + +#if DEBUG +@available(iOS 13, *) +struct SimpleView_Previews : PreviewProvider { + static var previews: some View { + SimpleView() + } +} +#endif diff --git a/iOS Sample/iOS Sample/SwiftUIViewController.storyboard b/iOS Sample/iOS Sample/SwiftUIViewController.storyboard new file mode 100644 index 0000000..9de8386 --- /dev/null +++ b/iOS Sample/iOS Sample/SwiftUIViewController.storyboard @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS Sample/iOS Sample/SwiftUIViewController.swift b/iOS Sample/iOS Sample/SwiftUIViewController.swift new file mode 100644 index 0000000..a9ce0b6 --- /dev/null +++ b/iOS Sample/iOS Sample/SwiftUIViewController.swift @@ -0,0 +1,73 @@ +// +// SwiftUIViewController.swift +// iOS Sample +// +// Created by Kazuhiro Hayashi on 6/22/1 R. +// Copyright © 2019 Kazuhiro Hayashi. All rights reserved. +// + +import UIKit +#if canImport(SwiftUI) +import SwiftUI +#endif + +class SwiftUIViewController: UIViewController { + @IBOutlet weak var tableView: UITableView! + + var dataSource = [ + "Simple" + ] + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + if let selectionIndexPath = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: selectionIndexPath, animated: animated) + } + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} + +extension SwiftUIViewController: UITableViewDataSource { + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) + cell.textLabel?.text = dataSource[indexPath.row] + return cell + + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + dataSource.count + } +} + +extension SwiftUIViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + switch dataSource[indexPath.row] { + case "Simple": + if #available(iOS 13, *) { + let vc = UIHostingController(rootView: SimpleView()) + navigationController?.pushViewController(vc, animated: true) + } else { + // Fallback on earlier versions + } + default: + break + } + } +} From 7618572ebc4c138c80034707fb23ee565cfe0d78 Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Sat, 22 Jun 2019 17:25:28 +0900 Subject: [PATCH 4/7] make MenuView --- iOS Sample/iOS Sample/SimpleView.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/iOS Sample/iOS Sample/SimpleView.swift b/iOS Sample/iOS Sample/SimpleView.swift index 87b3b01..8dde63b 100644 --- a/iOS Sample/iOS Sample/SimpleView.swift +++ b/iOS Sample/iOS Sample/SimpleView.swift @@ -7,11 +7,12 @@ // import SwiftUI +import PagingKit @available(iOS 13, *) struct SimpleView : View { var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello World!"/*@END_MENU_TOKEN@*/) + MenuView() } } @@ -23,3 +24,14 @@ struct SimpleView_Previews : PreviewProvider { } } #endif + + +struct MenuView: UIViewControllerRepresentable { + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { + return PagingMenuViewController() + } + + func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { + uiViewController.reloadData() + } +} From 21273e01ca990acfc17b5fde529c5830972e0dd0 Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Sun, 23 Jun 2019 16:32:37 +0900 Subject: [PATCH 5/7] update SwiftUI sample --- iOS Sample/iOS Sample/SimpleView.swift | 170 +++++++++++++++++- .../iOS Sample/SimpleViewController.swift | 4 +- 2 files changed, 167 insertions(+), 7 deletions(-) diff --git a/iOS Sample/iOS Sample/SimpleView.swift b/iOS Sample/iOS Sample/SimpleView.swift index 8dde63b..9dc33bb 100644 --- a/iOS Sample/iOS Sample/SimpleView.swift +++ b/iOS Sample/iOS Sample/SimpleView.swift @@ -12,7 +12,63 @@ import PagingKit @available(iOS 13, *) struct SimpleView : View { var body: some View { - MenuView() + VStack(spacing: 0) { + Menu([ + MenuElement(title: "1"), + MenuElement(title: "2"), + MenuElement(title: "3"), + MenuElement(title: "4"), + MenuElement(title: "5"), + MenuElement(title: "6"), + MenuElement(title: "7"), + MenuElement(title: "9"), + MenuElement(title: "10"), + MenuElement(title: "11"), + MenuElement(title: "12")]) { id in + MenuRow(title: id.title).frame(width: 100) + }.frame(height: 44) + + Content(controllers: [ + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()), + UIHostingController(rootView: SimpleList()) + ] + ) + }.edgesIgnoringSafeArea([.bottom, .leading, .trailing]) + } +} + +struct MenuElement: Identifiable { + let title: String + + var id: String { title } +} + +@available(iOS 13.0, *) +struct SimpleList: View { + var body: some View { + List { + ForEach(["🐶", "🐭", "🐱", "🐹", "🐰", "🦊","🐻","🐼","🐨","🐯","🐶", "🐭", "🐱", "🐹", "🐰", "🦊","🐻","🐼","🐨","🐯"].identified(by: \.self)) { text in + Text(text) + } + } + } +} + +@available(iOS 13.0, *) +struct MenuRow: View { + let title: String + + var body: some View { + Text(title) } } @@ -26,12 +82,116 @@ struct SimpleView_Previews : PreviewProvider { #endif -struct MenuView: UIViewControllerRepresentable { - func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { - return PagingMenuViewController() +@available(iOS 13.0, *) +struct Menu: UIViewControllerRepresentable where Data : RandomAccessCollection, Content: View, Data.Element : Identifiable, Data.Index == Int { + var data: Data + var content: (Data.Element.IdentifiedValue) -> Content + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + public init(_ data: Data, @ViewBuilder content: @escaping (Data.Element.IdentifiedValue) -> Content) { + self.data = data + self.content = content + } + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { + let vc = PagingMenuViewController() + vc.register(type: PagingMenuViewCell.self, forCellWithReuseIdentifier: "identifier") + vc.dataSource = context.coordinator + vc.delegate = context.coordinator + return vc + } + + func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { + uiViewController.reloadData() + } + + class Coordinator: PagingMenuViewControllerDelegate, PagingMenuViewControllerDataSource { + let sizingCell = PagingMenuViewCell(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) + + func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat { + let element = parent.data[index] + let content = parent.content(element.identifiedValue) + let controller = UIHostingController(rootView: content) + + sizingCell.subviews.forEach { $0.removeFromSuperview() } + sizingCell.addSubview(controller.view) + controller.view.translatesAutoresizingMaskIntoConstraints = false + controller.view.topAnchor.constraint(equalTo: sizingCell.topAnchor).isActive = true + controller.view.bottomAnchor.constraint(equalTo: sizingCell.bottomAnchor).isActive = true + controller.view.leadingAnchor.constraint(equalTo: sizingCell.leadingAnchor).isActive = true + controller.view.trailingAnchor.constraint(equalTo: sizingCell.trailingAnchor).isActive = true + let size = sizingCell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + return size.width + } + + func menuViewController(viewController: PagingMenuViewController, cellForItemAt index: Int) -> PagingMenuViewCell { + let element = parent.data[index] + let content = parent.content(element.identifiedValue) + let controller = UIHostingController(rootView: content) + + let cell = viewController.dequeueReusableCell(withReuseIdentifier: "identifier", for: index) + cell.subviews.forEach { $0.removeFromSuperview() } + cell.addSubview(controller.view) + controller.view.translatesAutoresizingMaskIntoConstraints = false + controller.view.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true + controller.view.bottomAnchor.constraint(equalTo: cell.bottomAnchor).isActive = true + controller.view.leadingAnchor.constraint(equalTo: cell.leadingAnchor).isActive = true + controller.view.trailingAnchor.constraint(equalTo: cell.trailingAnchor).isActive = true + return cell + } + + func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int) { + + } + + func numberOfItemsForMenuViewController(viewController: PagingMenuViewController) -> Int { + parent.data.count + } + + var parent: Menu + + init(_ vc: Menu) { + parent = vc + } + + } +} + +@available(iOS 13.0, *) +struct Content: UIViewControllerRepresentable { + var controllers: [UIViewController] + + func makeCoordinator() -> Coordinator { + Coordinator(self) } - func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingContentViewController { + let vc = PagingContentViewController() + vc.dataSource = context.coordinator + vc.delegate = context.coordinator + return vc + } + + func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { uiViewController.reloadData() } + + class Coordinator: PagingContentViewControllerDelegate, PagingContentViewControllerDataSource { + var parent: Content + + init(_ vc: Content) { + parent = vc + } + + func contentViewController(viewController: PagingContentViewController, viewControllerAt index: Int) -> UIViewController { + parent.controllers[index] + } + + func numberOfItemsForContentViewController(viewController: PagingContentViewController) -> Int { + parent.controllers.count + } + } } diff --git a/iOS Sample/iOS Sample/SimpleViewController.swift b/iOS Sample/iOS Sample/SimpleViewController.swift index e4ca3e5..b7997b1 100644 --- a/iOS Sample/iOS Sample/SimpleViewController.swift +++ b/iOS Sample/iOS Sample/SimpleViewController.swift @@ -45,7 +45,7 @@ class SimpleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - + menuViewController?.cellSpacing = 10 menuViewController?.register(type: TitleLabelMenuViewCell.self, forCellWithReuseIdentifier: "identifier") menuViewController?.registerFocusView(view: UnderlineFocusView()) contentViewController?.scrollView.bounces = true @@ -80,7 +80,7 @@ extension SimpleViewController: PagingMenuViewControllerDataSource { } func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat { - return viewController.view.bounds.width / CGFloat(dataSource.count) + return (viewController.view.bounds.width - viewController.menuView.totalSpacing) / CGFloat(dataSource.count) } var insets: UIEdgeInsets { From 59a60775103397aefdbb04bac1cfc465d11c0d1c Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Sun, 23 Jun 2019 20:42:59 +0900 Subject: [PATCH 6/7] add focusview --- iOS Sample/iOS Sample/SimpleView.swift | 88 ++++++++++++++++++++------ 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/iOS Sample/iOS Sample/SimpleView.swift b/iOS Sample/iOS Sample/SimpleView.swift index 9dc33bb..aa56228 100644 --- a/iOS Sample/iOS Sample/SimpleView.swift +++ b/iOS Sample/iOS Sample/SimpleView.swift @@ -11,9 +11,11 @@ import PagingKit @available(iOS 13, *) struct SimpleView : View { + @State var currentOffset: (index: Int, percent: Float) = (index: 0, percent: 0) + var body: some View { VStack(spacing: 0) { - Menu([ + Menu(data: [ MenuElement(title: "1"), MenuElement(title: "2"), MenuElement(title: "3"), @@ -24,7 +26,9 @@ struct SimpleView : View { MenuElement(title: "9"), MenuElement(title: "10"), MenuElement(title: "11"), - MenuElement(title: "12")]) { id in + MenuElement(title: "12")], + focus: Focus(), + currentOffset: $currentOffset) { id in MenuRow(title: id.title).frame(width: 100) }.frame(height: 44) @@ -40,7 +44,8 @@ struct SimpleView : View { UIHostingController(rootView: SimpleList()), UIHostingController(rootView: SimpleList()), UIHostingController(rootView: SimpleList()) - ] + ], + currentOffset: $currentOffset ) }.edgesIgnoringSafeArea([.bottom, .leading, .trailing]) } @@ -63,6 +68,16 @@ struct SimpleList: View { } } +@available(iOS 13.0, *) +struct Focus: View { + var body: some View { + VStack { + Spacer() + Rectangle().frame(height: 4).foregroundColor(.red) + } + } +} + @available(iOS 13.0, *) struct MenuRow: View { let title: String @@ -72,44 +87,55 @@ struct MenuRow: View { } } -#if DEBUG -@available(iOS 13, *) -struct SimpleView_Previews : PreviewProvider { - static var previews: some View { - SimpleView() - } -} -#endif +//#if DEBUG +//@available(iOS 13, *) +//struct SimpleView_Previews : PreviewProvider { +// static var previews: some View { +// SimpleView() +// } +//} +//#endif @available(iOS 13.0, *) -struct Menu: UIViewControllerRepresentable where Data : RandomAccessCollection, Content: View, Data.Element : Identifiable, Data.Index == Int { +struct Menu: UIViewControllerRepresentable where Data : RandomAccessCollection, Content: View, Focus: View, Data.Element : Identifiable, Data.Index == Int { var data: Data + var focus: Focus + @Binding var currentOffset: (index: Int, percent: Float) var content: (Data.Element.IdentifiedValue) -> Content func makeCoordinator() -> Coordinator { Coordinator(self) } - public init(_ data: Data, @ViewBuilder content: @escaping (Data.Element.IdentifiedValue) -> Content) { - self.data = data - self.content = content - } - func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { let vc = PagingMenuViewController() vc.register(type: PagingMenuViewCell.self, forCellWithReuseIdentifier: "identifier") vc.dataSource = context.coordinator vc.delegate = context.coordinator + let focusVc = UIHostingController(rootView: focus) + focusVc.view.backgroundColor = .clear + vc.registerFocusView(view: focusVc.view) + return vc } func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { - uiViewController.reloadData() + + if !context.coordinator.isReloaded { + uiViewController.reloadData(with: currentOffset.index, completionHandler: nil) + context.coordinator.isReloaded.toggle() + } else if !context.coordinator.isSelected { + print(currentOffset) + uiViewController.scroll(index: currentOffset.index, percent: CGFloat(currentOffset.percent), animated: false) + } + context.coordinator.isSelected = false } class Coordinator: PagingMenuViewControllerDelegate, PagingMenuViewControllerDataSource { let sizingCell = PagingMenuViewCell(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) + var isReloaded = false + var isSelected = false func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat { let element = parent.data[index] @@ -144,7 +170,8 @@ struct Menu: UIViewControllerRepresentable where Data : RandomAcc } func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int) { - + isSelected = true + parent.currentOffset = (index: page, percent: 0) } func numberOfItemsForMenuViewController(viewController: PagingMenuViewController) -> Int { @@ -156,13 +183,13 @@ struct Menu: UIViewControllerRepresentable where Data : RandomAcc init(_ vc: Menu) { parent = vc } - } } @available(iOS 13.0, *) struct Content: UIViewControllerRepresentable { var controllers: [UIViewController] + @Binding var currentOffset: (index: Int, percent: Float) func makeCoordinator() -> Coordinator { Coordinator(self) @@ -176,11 +203,18 @@ struct Content: UIViewControllerRepresentable { } func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { - uiViewController.reloadData() + if !context.coordinator.isReloaded { + uiViewController.reloadData() + context.coordinator.isReloaded.toggle() + } else if !context.coordinator.isManualScrolling { + uiViewController.scroll(to: currentOffset.index, animated: true) + } } class Coordinator: PagingContentViewControllerDelegate, PagingContentViewControllerDataSource { var parent: Content + var isReloaded = false + var isManualScrolling = false init(_ vc: Content) { parent = vc @@ -193,5 +227,17 @@ struct Content: UIViewControllerRepresentable { func numberOfItemsForContentViewController(viewController: PagingContentViewController) -> Int { parent.controllers.count } + + func contentViewController(viewController: PagingContentViewController, willBeginManualScrollOn index: Int) { + isManualScrolling = true + } + + func contentViewController(viewController: PagingContentViewController, didManualScrollOn index: Int, percent: CGFloat) { + parent.currentOffset = (index: index, percent: Float(percent)) + } + + func contentViewController(viewController: PagingContentViewController, didEndManualScrollOn index: Int) { + isManualScrolling = false + } } } From c83a3a53a03b90ee1e756f78ccc0d6c7292f99fa Mon Sep 17 00:00:00 2001 From: Kazuhiro Hayashi Date: Sun, 23 Jun 2019 20:57:29 +0900 Subject: [PATCH 7/7] divide files --- .../iOS Sample.xcodeproj/project.pbxproj | 16 ++ iOS Sample/iOS Sample/PagingContent.swift | 66 +++++ iOS Sample/iOS Sample/PagingMenu.swift | 99 ++++++++ iOS Sample/iOS Sample/SimpleView.swift | 237 ++++-------------- 4 files changed, 226 insertions(+), 192 deletions(-) create mode 100644 iOS Sample/iOS Sample/PagingContent.swift create mode 100644 iOS Sample/iOS Sample/PagingMenu.swift diff --git a/iOS Sample/iOS Sample.xcodeproj/project.pbxproj b/iOS Sample/iOS Sample.xcodeproj/project.pbxproj index 5c44e07..a2d1c67 100644 --- a/iOS Sample/iOS Sample.xcodeproj/project.pbxproj +++ b/iOS Sample/iOS Sample.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 2B11E7D622BF9FE900B54860 /* PagingMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B11E7D522BF9FE900B54860 /* PagingMenu.swift */; }; + 2B11E7D822BFA01000B54860 /* PagingContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B11E7D722BFA01000B54860 /* PagingContent.swift */; }; 2B140598218EB84C00474615 /* NavigationBarMenuCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B140597218EB84C00474615 /* NavigationBarMenuCell.xib */; }; 2B14059A218EB8A000474615 /* NavigationBarMenuCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B140599218EB8A000474615 /* NavigationBarMenuCell.swift */; }; 2B14059C218EBAC200474615 /* NavigationBarFocusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B14059B218EBAC200474615 /* NavigationBarFocusView.swift */; }; @@ -101,6 +103,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2B11E7D522BF9FE900B54860 /* PagingMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingMenu.swift; sourceTree = ""; }; + 2B11E7D722BFA01000B54860 /* PagingContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingContent.swift; sourceTree = ""; }; 2B140597218EB84C00474615 /* NavigationBarMenuCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NavigationBarMenuCell.xib; sourceTree = ""; }; 2B140599218EB8A000474615 /* NavigationBarMenuCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarMenuCell.swift; sourceTree = ""; }; 2B14059B218EBAC200474615 /* NavigationBarFocusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarFocusView.swift; sourceTree = ""; }; @@ -196,6 +200,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2B11E7D322BF9F9800B54860 /* Wrapper */ = { + isa = PBXGroup; + children = ( + 2B11E7D522BF9FE900B54860 /* PagingMenu.swift */, + 2B11E7D722BFA01000B54860 /* PagingContent.swift */, + ); + name = Wrapper; + sourceTree = ""; + }; 2B14059F218EBD7200474615 /* NavigationBar */ = { isa = PBXGroup; children = ( @@ -354,6 +367,7 @@ 2BEDEC0122BE1240001B29D9 /* SwiftUI */ = { isa = PBXGroup; children = ( + 2B11E7D322BF9F9800B54860 /* Wrapper */, 2BEDEC0322BE1270001B29D9 /* SimpleView.swift */, 2BEDEC0922BE16D1001B29D9 /* SwiftUIViewController.storyboard */, 2BEDEC0B22BE1747001B29D9 /* SwiftUIViewController.swift */, @@ -628,7 +642,9 @@ 2BEDEC0422BE1270001B29D9 /* SimpleView.swift in Sources */, 2B47E7341F109DE400D67C04 /* OverlayFocusView.swift in Sources */, 2BC1B4181F19F29800829D1A /* TagViewController.swift in Sources */, + 2B11E7D822BFA01000B54860 /* PagingContent.swift in Sources */, 2B4F03501F90575B0015FCC8 /* ContentTableViewController.swift in Sources */, + 2B11E7D622BF9FE900B54860 /* PagingMenu.swift in Sources */, 2B3C7CC51F8CEB0100A43223 /* TwoLineMenuViewController.swift in Sources */, 2BC1B41A1F19F4CB00829D1A /* TagMenuCell.swift in Sources */, 2B47E7361F10A15700D67C04 /* OverlayMenuCell.swift in Sources */, diff --git a/iOS Sample/iOS Sample/PagingContent.swift b/iOS Sample/iOS Sample/PagingContent.swift new file mode 100644 index 0000000..f218565 --- /dev/null +++ b/iOS Sample/iOS Sample/PagingContent.swift @@ -0,0 +1,66 @@ +// +// PagingContent.swift +// iOS Sample +// +// Created by Kazuhiro Hayashi on 6/23/1 R. +// Copyright © 1 Reiwa Kazuhiro Hayashi. All rights reserved. +// + +import SwiftUI +import PagingKit + +@available(iOS 13.0, *) +struct PagingContent: UIViewControllerRepresentable { + var controllers: [UIViewController] + @Binding var currentOffset: (index: Int, percent: Float) + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingContentViewController { + let vc = PagingContentViewController() + vc.dataSource = context.coordinator + vc.delegate = context.coordinator + return vc + } + + func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { + if !context.coordinator.isReloaded { + uiViewController.reloadData() + context.coordinator.isReloaded.toggle() + } else if !context.coordinator.isManualScrolling { + uiViewController.scroll(to: currentOffset.index, animated: true) + } + } + + class Coordinator: PagingContentViewControllerDelegate, PagingContentViewControllerDataSource { + var parent: PagingContent + var isReloaded = false + var isManualScrolling = false + + init(_ vc: PagingContent) { + parent = vc + } + + func contentViewController(viewController: PagingContentViewController, viewControllerAt index: Int) -> UIViewController { + parent.controllers[index] + } + + func numberOfItemsForContentViewController(viewController: PagingContentViewController) -> Int { + parent.controllers.count + } + + func contentViewController(viewController: PagingContentViewController, willBeginManualScrollOn index: Int) { + isManualScrolling = true + } + + func contentViewController(viewController: PagingContentViewController, didManualScrollOn index: Int, percent: CGFloat) { + parent.currentOffset = (index: index, percent: Float(percent)) + } + + func contentViewController(viewController: PagingContentViewController, didEndManualScrollOn index: Int) { + isManualScrolling = false + } + } +} diff --git a/iOS Sample/iOS Sample/PagingMenu.swift b/iOS Sample/iOS Sample/PagingMenu.swift new file mode 100644 index 0000000..c39ada4 --- /dev/null +++ b/iOS Sample/iOS Sample/PagingMenu.swift @@ -0,0 +1,99 @@ +// +// PagingMenu.swift +// iOS Sample +// +// Created by Kazuhiro Hayashi on 6/23/1 R. +// Copyright © 1 Reiwa Kazuhiro Hayashi. All rights reserved. +// + +import SwiftUI +import PagingKit + +@available(iOS 13.0, *) +struct PagingMenu: UIViewControllerRepresentable where Data : RandomAccessCollection, Content: View, Focus: View, Data.Element : Identifiable, Data.Index == Int { + var data: Data + var focus: Focus + @Binding var currentOffset: (index: Int, percent: Float) + var content: (Data.Element.IdentifiedValue) -> Content + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { + let vc = PagingMenuViewController() + vc.register(type: PagingMenuViewCell.self, forCellWithReuseIdentifier: "identifier") + vc.dataSource = context.coordinator + vc.delegate = context.coordinator + let focusVc = UIHostingController(rootView: focus) + focusVc.view.backgroundColor = .clear + vc.registerFocusView(view: focusVc.view) + + return vc + } + + func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { + + if !context.coordinator.isReloaded { + uiViewController.reloadData(with: currentOffset.index, completionHandler: nil) + context.coordinator.isReloaded.toggle() + } else if !context.coordinator.isSelected { + print(currentOffset) + uiViewController.scroll(index: currentOffset.index, percent: CGFloat(currentOffset.percent), animated: false) + } + context.coordinator.isSelected = false + } + + class Coordinator: PagingMenuViewControllerDelegate, PagingMenuViewControllerDataSource { + let sizingCell = PagingMenuViewCell(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) + var isReloaded = false + var isSelected = false + + func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat { + let element = parent.data[index] + let content = parent.content(element.identifiedValue) + let controller = UIHostingController(rootView: content) + + sizingCell.subviews.forEach { $0.removeFromSuperview() } + sizingCell.addSubview(controller.view) + controller.view.translatesAutoresizingMaskIntoConstraints = false + controller.view.topAnchor.constraint(equalTo: sizingCell.topAnchor).isActive = true + controller.view.bottomAnchor.constraint(equalTo: sizingCell.bottomAnchor).isActive = true + controller.view.leadingAnchor.constraint(equalTo: sizingCell.leadingAnchor).isActive = true + controller.view.trailingAnchor.constraint(equalTo: sizingCell.trailingAnchor).isActive = true + let size = sizingCell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + return size.width + } + + func menuViewController(viewController: PagingMenuViewController, cellForItemAt index: Int) -> PagingMenuViewCell { + let element = parent.data[index] + let content = parent.content(element.identifiedValue) + let controller = UIHostingController(rootView: content) + + let cell = viewController.dequeueReusableCell(withReuseIdentifier: "identifier", for: index) + cell.subviews.forEach { $0.removeFromSuperview() } + cell.addSubview(controller.view) + controller.view.translatesAutoresizingMaskIntoConstraints = false + controller.view.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true + controller.view.bottomAnchor.constraint(equalTo: cell.bottomAnchor).isActive = true + controller.view.leadingAnchor.constraint(equalTo: cell.leadingAnchor).isActive = true + controller.view.trailingAnchor.constraint(equalTo: cell.trailingAnchor).isActive = true + return cell + } + + func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int) { + isSelected = true + parent.currentOffset = (index: page, percent: 0) + } + + func numberOfItemsForMenuViewController(viewController: PagingMenuViewController) -> Int { + parent.data.count + } + + var parent: PagingMenu + + init(_ vc: PagingMenu) { + parent = vc + } + } +} diff --git a/iOS Sample/iOS Sample/SimpleView.swift b/iOS Sample/iOS Sample/SimpleView.swift index aa56228..b2b8ab6 100644 --- a/iOS Sample/iOS Sample/SimpleView.swift +++ b/iOS Sample/iOS Sample/SimpleView.swift @@ -2,63 +2,20 @@ // SimpleView.swift // iOS Sample // -// Created by kahayash on 6/22/1 R. +// Created by Kazuhiro Hayashi on 6/22/1 R. // Copyright © 2019 Kazuhiro Hayashi. All rights reserved. // import SwiftUI import PagingKit -@available(iOS 13, *) -struct SimpleView : View { - @State var currentOffset: (index: Int, percent: Float) = (index: 0, percent: 0) - - var body: some View { - VStack(spacing: 0) { - Menu(data: [ - MenuElement(title: "1"), - MenuElement(title: "2"), - MenuElement(title: "3"), - MenuElement(title: "4"), - MenuElement(title: "5"), - MenuElement(title: "6"), - MenuElement(title: "7"), - MenuElement(title: "9"), - MenuElement(title: "10"), - MenuElement(title: "11"), - MenuElement(title: "12")], - focus: Focus(), - currentOffset: $currentOffset) { id in - MenuRow(title: id.title).frame(width: 100) - }.frame(height: 44) - - Content(controllers: [ - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()), - UIHostingController(rootView: SimpleList()) - ], - currentOffset: $currentOffset - ) - }.edgesIgnoringSafeArea([.bottom, .leading, .trailing]) - } -} - struct MenuElement: Identifiable { let title: String - var id: String { title } } @available(iOS 13.0, *) -struct SimpleList: View { +struct EmojiList: View { var body: some View { List { ForEach(["🐶", "🐭", "🐱", "🐹", "🐰", "🦊","🐻","🐼","🐨","🐯","🐶", "🐭", "🐱", "🐹", "🐰", "🦊","🐻","🐼","🐨","🐯"].identified(by: \.self)) { text in @@ -87,157 +44,53 @@ struct MenuRow: View { } } -//#if DEBUG -//@available(iOS 13, *) -//struct SimpleView_Previews : PreviewProvider { -// static var previews: some View { -// SimpleView() -// } -//} -//#endif - - -@available(iOS 13.0, *) -struct Menu: UIViewControllerRepresentable where Data : RandomAccessCollection, Content: View, Focus: View, Data.Element : Identifiable, Data.Index == Int { - var data: Data - var focus: Focus - @Binding var currentOffset: (index: Int, percent: Float) - var content: (Data.Element.IdentifiedValue) -> Content - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingMenuViewController { - let vc = PagingMenuViewController() - vc.register(type: PagingMenuViewCell.self, forCellWithReuseIdentifier: "identifier") - vc.dataSource = context.coordinator - vc.delegate = context.coordinator - let focusVc = UIHostingController(rootView: focus) - focusVc.view.backgroundColor = .clear - vc.registerFocusView(view: focusVc.view) - - return vc - } - - func updateUIViewController(_ uiViewController: PagingMenuViewController, context: UIViewControllerRepresentableContext) { - - if !context.coordinator.isReloaded { - uiViewController.reloadData(with: currentOffset.index, completionHandler: nil) - context.coordinator.isReloaded.toggle() - } else if !context.coordinator.isSelected { - print(currentOffset) - uiViewController.scroll(index: currentOffset.index, percent: CGFloat(currentOffset.percent), animated: false) - } - context.coordinator.isSelected = false - } +@available(iOS 13, *) +struct SimpleView : View { + @State var currentOffset: (index: Int, percent: Float) = (index: 0, percent: 0) - class Coordinator: PagingMenuViewControllerDelegate, PagingMenuViewControllerDataSource { - let sizingCell = PagingMenuViewCell(frame: CGRect(x: 0, y: 0, width: 1, height: 1)) - var isReloaded = false - var isSelected = false - - func menuViewController(viewController: PagingMenuViewController, widthForItemAt index: Int) -> CGFloat { - let element = parent.data[index] - let content = parent.content(element.identifiedValue) - let controller = UIHostingController(rootView: content) - - sizingCell.subviews.forEach { $0.removeFromSuperview() } - sizingCell.addSubview(controller.view) - controller.view.translatesAutoresizingMaskIntoConstraints = false - controller.view.topAnchor.constraint(equalTo: sizingCell.topAnchor).isActive = true - controller.view.bottomAnchor.constraint(equalTo: sizingCell.bottomAnchor).isActive = true - controller.view.leadingAnchor.constraint(equalTo: sizingCell.leadingAnchor).isActive = true - controller.view.trailingAnchor.constraint(equalTo: sizingCell.trailingAnchor).isActive = true - let size = sizingCell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - return size.width - } - - func menuViewController(viewController: PagingMenuViewController, cellForItemAt index: Int) -> PagingMenuViewCell { - let element = parent.data[index] - let content = parent.content(element.identifiedValue) - let controller = UIHostingController(rootView: content) + var body: some View { + VStack(spacing: 0) { + PagingMenu(data: [ + MenuElement(title: "1"), + MenuElement(title: "2"), + MenuElement(title: "3"), + MenuElement(title: "4"), + MenuElement(title: "5"), + MenuElement(title: "6"), + MenuElement(title: "7"), + MenuElement(title: "9"), + MenuElement(title: "10"), + MenuElement(title: "11"), + MenuElement(title: "12")], + focus: Focus(), + currentOffset: $currentOffset) { id in + MenuRow(title: id.title).frame(width: 100) + }.frame(height: 44) - let cell = viewController.dequeueReusableCell(withReuseIdentifier: "identifier", for: index) - cell.subviews.forEach { $0.removeFromSuperview() } - cell.addSubview(controller.view) - controller.view.translatesAutoresizingMaskIntoConstraints = false - controller.view.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true - controller.view.bottomAnchor.constraint(equalTo: cell.bottomAnchor).isActive = true - controller.view.leadingAnchor.constraint(equalTo: cell.leadingAnchor).isActive = true - controller.view.trailingAnchor.constraint(equalTo: cell.trailingAnchor).isActive = true - return cell - } - - func menuViewController(viewController: PagingMenuViewController, didSelect page: Int, previousPage: Int) { - isSelected = true - parent.currentOffset = (index: page, percent: 0) - } - - func numberOfItemsForMenuViewController(viewController: PagingMenuViewController) -> Int { - parent.data.count - } - - var parent: Menu - - init(_ vc: Menu) { - parent = vc - } + PagingContent(controllers: [ + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()), + UIHostingController(rootView: EmojiList()) + ], + currentOffset: $currentOffset + ) + }.edgesIgnoringSafeArea([.bottom, .leading, .trailing]) } } -@available(iOS 13.0, *) -struct Content: UIViewControllerRepresentable { - var controllers: [UIViewController] - @Binding var currentOffset: (index: Int, percent: Float) - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> PagingContentViewController { - let vc = PagingContentViewController() - vc.dataSource = context.coordinator - vc.delegate = context.coordinator - return vc - } - - func updateUIViewController(_ uiViewController: PagingContentViewController, context: UIViewControllerRepresentableContext) { - if !context.coordinator.isReloaded { - uiViewController.reloadData() - context.coordinator.isReloaded.toggle() - } else if !context.coordinator.isManualScrolling { - uiViewController.scroll(to: currentOffset.index, animated: true) - } - } - - class Coordinator: PagingContentViewControllerDelegate, PagingContentViewControllerDataSource { - var parent: Content - var isReloaded = false - var isManualScrolling = false - - init(_ vc: Content) { - parent = vc - } - - func contentViewController(viewController: PagingContentViewController, viewControllerAt index: Int) -> UIViewController { - parent.controllers[index] - } - - func numberOfItemsForContentViewController(viewController: PagingContentViewController) -> Int { - parent.controllers.count - } - - func contentViewController(viewController: PagingContentViewController, willBeginManualScrollOn index: Int) { - isManualScrolling = true - } - - func contentViewController(viewController: PagingContentViewController, didManualScrollOn index: Int, percent: CGFloat) { - parent.currentOffset = (index: index, percent: Float(percent)) - } - - func contentViewController(viewController: PagingContentViewController, didEndManualScrollOn index: Int) { - isManualScrolling = false - } +#if DEBUG +@available(iOS 13, *) +struct SimpleView_Previews : PreviewProvider { + static var previews: some View { + SimpleView() } } +#endif