How to make radio button group in SwiftUI

Issue #592

Use picker with Radio style

Hard to customize

1
2
3
4
Picker(selection: Binding<Bool>.constant(true), label: EmptyView()) {
Text("Production").tag(0)
Text("Sandbox").tag(1)
}.pickerStyle(RadioGroupPickerStyle())

Use custom view

Use contentShape to make whole button tappable.
Make custom Binding for our enum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
struct EnvironmentView: View {
@Binding var input: Input

var body: some View {
VStack(alignment: .leading) {
RadioButton(text: "Production", isOn: binding(for: .production))
RadioButton(text: "Sandbox", isOn: binding(for: .sandbox))
}
}

private func binding(for environment: Input.Environment) -> Binding<Bool> {
Binding<Bool>(
get: { self.input.environment == environment },
set: { flag in
if flag {
self.input.environment = environment
}
}
)
}
}

struct RadioButton: View {
let text: String
@Binding var isOn: Bool

var body: some View {
Button(action: {
self.isOn.toggle()
}) {
HStack(alignment: .top) {
Circle()
.fill(isOn ? R.color.primary : Color.clear)
.overlay(Circle().stroke(R.color.primary))
.frame(width: 18, height: 18)
Text(text)
.foregroundColor(R.color.text)
}
.contentShape(Rectangle())
}
.buttonStyle(RadioButtonStyle())
}
}

struct RadioButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding(.vertical, 4)
.padding(.horizontal, 8)
.border(SeparatorShapeStyle(), width: 0)
.background(Color.clear)
}
}

Comments