Created
December 7, 2019 15:54
-
-
Save jemmons/2d0f80ebed382f07adb6cc9f6a9afa6d to your computer and use it in GitHub Desktop.
SwiftUI view that will either ForEach over data or display given view if empty.
This file contains hidden or 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
import SwiftUI | |
struct ForEachOrEmpty<Data, ID, ForEachContent, EmptyContent>: View where Data: RandomAccessCollection, ID: Hashable, ForEachContent: View, EmptyContent: View { | |
let data: Data | |
let forEachBuilder: (Data.Element) -> ForEachContent | |
let emptyBuilder: () -> EmptyContent | |
let identityKeyPath: KeyPath<Data.Element, ID> | |
init(_ data: Data, id: KeyPath<Data.Element, ID>, @ViewBuilder each: @escaping (Data.Element)->ForEachContent, @ViewBuilder empty: @escaping () -> EmptyContent) { | |
self.data = data | |
identityKeyPath = id | |
forEachBuilder = each | |
emptyBuilder = empty | |
} | |
var body: some View { | |
if data.isEmpty { | |
return AnyView(emptyBuilder()) | |
} else { | |
return AnyView(ForEach(data, id: identityKeyPath, content: forEachBuilder)) | |
} | |
} | |
} | |
extension ForEachOrEmpty where ID == Data.Element.ID, Data.Element: Identifiable { | |
init(_ data: Data, @ViewBuilder each: @escaping (Data.Element)->ForEachContent, @ViewBuilder empty: @escaping () -> EmptyContent) { | |
self.init(data, id: \.id , each: each, empty: empty) | |
} | |
} | |
struct ForEachOrEmpty_Previews: PreviewProvider { | |
static let someNumbers = [1,2,3] | |
static let noNumbers: [Int] = [] | |
struct IDString: Identifiable { | |
let value: String | |
var id: String { value } | |
init(_ value: String) { self.value = value } | |
} | |
static let someLetters = [IDString("a"), IDString("b"), IDString("c")] | |
static let noLetters: [IDString] = [] | |
static var previews: some View { | |
Group { | |
VStack { | |
Divider() | |
ForEachOrEmpty(someNumbers, id: \.self, each: { number in | |
VStack { | |
Text("number \(number)") | |
Divider() | |
} | |
}, empty: { | |
VStack { | |
Text("None") | |
Divider() | |
} | |
}) | |
} | |
VStack { | |
Divider() | |
ForEachOrEmpty(noNumbers, id: \.self, each: { number in | |
VStack { | |
Text("number \(number)") | |
Divider() | |
} | |
}, empty: { | |
VStack { | |
Text("None") | |
Divider() | |
} | |
}) | |
} | |
VStack { | |
Divider() | |
ForEachOrEmpty(someLetters, each: { letter in | |
VStack { | |
Text(letter.value) | |
Divider() | |
} | |
}, empty: { | |
VStack { | |
Text("None") | |
Divider() | |
} | |
}) | |
} | |
VStack { | |
Divider() | |
ForEachOrEmpty(noLetters, each: { letter in | |
VStack { | |
Text(letter.value) | |
Divider() | |
} | |
}, empty: { | |
VStack { | |
Text("None") | |
Divider() | |
} | |
}) | |
} | |
}.previewLayout(.sizeThatFits) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment