Created
April 7, 2021 23:04
-
-
Save sbeitzel/a203a6343d6fec7076234149e775f6fb to your computer and use it in GitHub Desktop.
SwiftUI multiple selection list
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 | |
/// UI View which presents a list of items, any number of which may | |
/// be selected. Each item must conform to `Identifiable` and | |
/// to `Hashable`. | |
struct MultiSelectItemList<T: Identifiable & Hashable>: View { | |
private let items: [T] | |
private let modified: (Set<T>) -> Void | |
private let itemString: (T) -> String | |
@State private var selected: Set<T> | |
/// Initialize a MultiSelectItemList | |
/// | |
/// - Parameters: | |
/// - items: the items to be displayed | |
/// - selected: the currently selected items | |
/// - modified: callback, called when the selection changes | |
/// - itemString: method to get a displayable string label for a given item | |
init(items: [T], selected: Set<T>, modified: @escaping (Set<T>) -> Void, itemString: @escaping (T) -> String) { | |
self.items = items | |
self.modified = modified | |
self.itemString = itemString | |
_selected = State(wrappedValue: selected) | |
} | |
var body: some View { | |
ScrollView { | |
ForEach(items) { item in | |
MultiSelectItemRow( | |
item: item, | |
selected: selected.contains(item), | |
action: { | |
if selected.contains(item) { | |
selected.remove(item) | |
} else { | |
selected.insert(item) | |
} | |
modified(selected) | |
}, | |
itemString: itemString | |
) | |
} | |
} | |
} | |
} |
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 MultiSelectItemRow<T>: View { | |
let item: T | |
let selected: Bool | |
let action: () -> Void | |
let itemString: (T) -> String | |
var body: some View { | |
HStack { | |
icon | |
Text(itemString(item)) | |
Spacer() | |
} | |
.background(background) | |
.onTapGesture { | |
action() | |
} | |
} | |
var background: Color { | |
if selected { | |
return .accentColor | |
} else { | |
return .clear | |
} | |
} | |
var icon: some View { | |
ZStack { | |
if selected { | |
Image(systemName: "checkmark.circle") | |
} | |
EmptyView() | |
} | |
.frame(width: 30, height: 20, alignment: .center) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment