Created
May 7, 2020 13:14
-
-
Save yrave/1797f2e66b7e1e328cd5b8500d913cdd to your computer and use it in GitHub Desktop.
SwiftUI - Flexible Navigation with Coordinators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MainView.swift | |
// SwiftUI Avoid Navigation Hardcoded | |
// | |
// Created by Yannick Rave on 07.05.20. | |
// Copyright © 2020 Rave. All rights reserved. | |
// | |
import SwiftUI | |
struct ItalicTextView: View { | |
var text: String | |
var body: some View { | |
Text(text) | |
.italic() | |
} | |
} | |
struct BoldTextView: View { | |
var text: String | |
var body: some View { | |
Text(text) | |
.bold() | |
} | |
} | |
struct ItalicTextViewCoordinator { | |
var text: String | |
func createView() -> ItalicTextView { | |
return ItalicTextView(text: text) | |
} | |
} | |
struct BoldTextViewCoordinator { | |
var text: String | |
func createView() -> BoldTextView { | |
return BoldTextView(text: text) | |
} | |
} | |
// Not reusable if you want to change the destination | |
struct NotReusableTextView: View { | |
var text: String | |
var body: some View { | |
VStack { | |
Text(text) | |
NavigationLink("Link", destination: BoldTextView(text: text)) | |
} | |
} | |
} | |
// A lot of nested code and dependencies | |
struct NestedMainView: View { | |
@State var text: String | |
var body: some View { | |
ReusableNavigationLinkTextView( | |
text: self.text, | |
destination: { | |
ReusableNavigationLinkTextView( | |
text: self.text, | |
destination: { | |
BoldTextView(text: self.text) | |
} | |
) | |
} | |
) | |
} | |
} | |
protocol ReusableNavigationLinkTextViewCoordinator { | |
associatedtype Destination: View | |
var destination: () -> Destination { get } | |
func createView() -> ReusableNavigationLinkTextView<Destination> | |
} | |
struct ReusableNavigationLinkShowBoldViewCoordinator: ReusableNavigationLinkTextViewCoordinator { | |
@Binding var text: String | |
var destination: () -> BoldTextView { | |
{ return BoldTextView(text: self.text) } | |
} | |
func createView() -> ReusableNavigationLinkTextView<Destination> { | |
return ReusableNavigationLinkTextView(text: self.text, destination: self.destination) | |
} | |
} | |
struct ReusableNavigationLinkShowItalicViewCoordinator: ReusableNavigationLinkTextViewCoordinator { | |
@Binding var text: String | |
var destination: () -> ItalicTextView { | |
{ return ItalicTextView(text: self.text) } | |
} | |
func createView() -> ReusableNavigationLinkTextView<Destination> { | |
return ReusableNavigationLinkTextView(text: self.text, destination: self.destination) | |
} | |
} | |
struct ShowNavigationLinkUntilNumberGreaterFourThenItalicViewCoordinator: ReusableNavigationLinkTextViewCoordinator { | |
@Binding var text: String | |
let number: Int | |
private var isNumberGreaterThan4: Bool { | |
return number > 4 | |
} | |
var destination: () -> AnyView { | |
{ | |
if self.isNumberGreaterThan4 { | |
let coordinator = ItalicTextViewCoordinator(text: self.text) | |
return AnyView( | |
coordinator.createView() | |
) | |
} else { | |
let coordinator = ShowNavigationLinkUntilNumberGreaterFourThenItalicViewCoordinator( | |
text: self.$text, | |
number: self.number + 1 | |
) | |
return AnyView(coordinator.createView()) | |
} | |
} | |
} | |
func createView() -> ReusableNavigationLinkTextView<AnyView> { | |
return ReusableNavigationLinkTextView(text: self.text, destination: self.destination) | |
} | |
} | |
struct ReusableNavigationLinkTextView<Destination: View>: View { | |
var text: String | |
var destination: () -> Destination | |
var body: some View { | |
VStack { | |
Text(text) | |
NavigationLink("Link", destination: self.destination()) | |
} | |
} | |
} | |
struct MainView: View { | |
@State var text = "Main" | |
var body: some View { | |
NavigationView { | |
VStack(spacing: 32) { | |
NavigationLink("Bold", destination: self.reuseThenBoldChild()) | |
NavigationLink("Reuse then Italic", destination: self.reuseThenItalicChild()) | |
NavigationLink("Greater Four", destination: self.numberGreaterFourChild()) | |
NavigationLink("Text Field", destination: self.textField()) | |
} | |
} | |
} | |
func reuseThenBoldChild() -> some View { | |
let coordinator = ReusableNavigationLinkShowBoldViewCoordinator(text: self.$text) | |
return coordinator.createView() | |
} | |
func reuseThenItalicChild() -> some View { | |
let coordinator = ReusableNavigationLinkShowItalicViewCoordinator(text: self.$text) | |
return coordinator.createView() | |
} | |
func numberGreaterFourChild() -> some View { | |
let coordinator = ShowNavigationLinkUntilNumberGreaterFourThenItalicViewCoordinator(text: self.$text, number: 1) | |
return coordinator.createView() | |
} | |
func textField() -> some View { | |
let coordinator = TextFieldEmptyReusableViewCoordinator(text: self.$text) | |
return coordinator.createView() | |
} | |
} | |
struct BoldNavigationLink: View { | |
let text = "Text" | |
var body: some View { | |
ReusableNavigationLinkTextView( | |
text: self.text, | |
destination: { BoldTextView(text: self.text) } | |
) | |
} | |
} | |
struct TextFieldEmptyReusableViewCoordinator { | |
@Binding var text: String | |
func createView() -> some View { | |
let reusableViewBoldCoordinator = ReusableNavigationLinkShowBoldViewCoordinator(text: self.$text) | |
let reusableView = reusableViewBoldCoordinator.createView() | |
let emptyView = EmptyNavigationLinkView(destination: { reusableView }) | |
let textField = TextFieldView(text: self.$text, destination: { emptyView }) | |
return textField | |
} | |
} | |
struct TextFieldView<Destination: View>: View { | |
@Binding var text: String | |
var destination: () -> Destination | |
var body: some View { | |
VStack { | |
TextField("Text", text: self.$text) | |
NavigationLink("Next", destination: self.destination()) | |
} | |
} | |
} | |
struct EmptyNavigationLinkView<Destination: View>: View { | |
var destination: () -> Destination | |
var body: some View { | |
NavigationLink("Next", destination: self.destination()) | |
} | |
} | |
struct MainView_Previews: PreviewProvider { | |
static var previews: some View { | |
MainView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment