# ๐ฅจ ์ฒดํฌ๋ฐ์ค ๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด
SwiftUI ์์ ์ ๊ณตํ๋ Toggle ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ SF Symbol์ ์ด๋ฏธ์ง๋ฅผ ํ์ฉํด ํด๋ฆญํ ๋๋ง๋ค ์ ํํด์ฃผ๋ฉด์ ์ฒดํฌ๋ฐ์ค๋ฅผ ๊ตฌํํด์ค ์ ์๋ค. ์ฝ๋ ์์๋ ์๋์ ๊ฐ๋ค.
import SwiftUI
struct MyTag {
let label : String
let value : Int
}
struct ToggleStylePracticeView: View {
@State var selectedTopics : [String] = ["tag1", "tag3"]
let myTags : [MyTag] = [
MyTag(label: "tag1", value: 1),
MyTag(label: "tag2", value: 2),
MyTag(label: "tag3", value: 3),
MyTag(label: "tag4", value: 4),
MyTag(label: "tag5", value: 5),
]
var body: some View {
VStack(alignment: .leading, spacing: 0){
ForEach(myTags.map{$0.label}, id : \.self){el in
VStack(spacing: 0){
HStack{
Button{
if(selectedTopics.contains(el)){
selectedTopics = selectedTopics.filter{topic in topic != el}
}else{
selectedTopics.append(el)
}
}label : {
HStack(alignment: .center){
selectedTopics.contains(el)
? Image(systemName: "checkmark.circle.fill")
.imageScale(.large)
.foregroundColor(.green)
: Image(systemName: "circle")
.imageScale(.large)
.foregroundColor(.green)
Text(el)
.foregroundColor(.black)
Spacer()
}
.padding(5)
}
Spacer()
}
Divider()
.padding(.bottom,5)
}
}
}
}
}
ํ์ง๋ง ๋งค๋ฒ ์ฒดํฌ๋ฐ์ค๋ฅผ ์ด๋ ๊ฒ ๋ง๋ ๋ค๋ฉด ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ธฐ๋ ํ๊ณ ์ ํํ ์ ์ฝ๋์์ ๋ฌด์์ ํ๊ณ ์ถ์์ง ์๋๋ฅผ ํ์ ํ๊ธฐ ์ค๋๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ToggleStyle ํ๋กํ ์ฝ์ ์์๋ฐ์ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ชจ๋ํ ํ์ฌ ๋ค์ํ ๋ชจ์์ ์ฒดํฌ๋ฐ์ค, ํ ๊ธ ๋ฒํผ์ ๋ง๋ค์ด์ฃผ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
# ๐ฅจ SwiftUI์์ ์ ๊ณตํ๋ Toggle View ์ฌ์ฉํ๊ธฐ
์ ํ ๊ณต์๋ฌธ์์์๋ Toggle View๋ฅผ ์ด๋ ๊ฒ ์ค๋ช ํ๊ณ ์๋ค.
https://developer.apple.com/documentation/swiftui/toggle
Toggle | Apple Developer Documentation
A control that toggles between on and off states.
developer.apple.com
์๋์ ์์์ฝ๋ ์ฒ๋ผ ์ฌ์ฉํ ์ ์๊ณ label ํ๋ผ๋ฏธํฐ์ ๋ํ ์ธ์๋ ํํํด๋ก์ ๋ก์ ์ ๋ฌํ ์ ์๋ค.
import SwiftUI
struct ToggleStylePracticeView: View {
@State var isOn = false
var body: some View {
VStack {
Toggle(isOn: self.$isOn) {
Text("Toggle: \(String(self.isOn))")
}
.toggleStyle(.automatic) // .automatic, .button, .switch ์ธ๊ฐ์ง ์คํ์ผ๋ง ์ง์ํ๋ค
}
}
}
ํ์ง๋ง, ์ด๋ ๊ฒ ๊ธฐ๋ณธ ํ ๊ธ ๋ทฐ์ ๋ํด์๋ ์ ์ฝ๋๋ธ๋ญ์์ ์ฃผ์์ผ๋ก ๋งํ ๊ฒ์ฒ๋ผ ์ธ๊ฐ์ง ํ ๊ธ ์คํ์ผ๋ง์ ์ง์ํ๋ค. ๊ทธ๋ ๊ธฐ๋๋ฌธ์ Toggle View๋ฅผ ํ์ฉํด์ ์ฌ๋ฌ ๋ชจ์์ ์ฒดํฌ๋ฐ์ค๋ฅผ ๊ตฌํํด์ฃผ๊ธฐ ์ํด์ ์ฌ์ฉํด์ฃผ๋๊ฒ ๋ฐ๋ก ToggleStyle ํ๋กํ ์ฝ์ด๋ค.
# ๐ฅจ ToggleStyle ํ๋กํ ์ฝ์ ํ์ฉํ์ฌ ์ปค์คํ ํ ๊ธ ๋ฒํผ ๋ง๋๋ ๋ฐฉ๋ฒ
https://developer.apple.com/documentation/swiftui/togglestyle
ToggleStyle | Apple Developer Documentation
The appearance and behavior of a toggle.
developer.apple.com
1) ์ฐ์ ํ ๊ธ์ ์ปค์คํ ์คํ์ผ์ ์ ์ฉํด์ฃผ๋ ค๋ฉด ToggleStyle ํ๋กํ ์ฝ์ ์ค์ํ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ์ ์ํด์ฃผ๊ณ , makeBody(configuration:) -> some View ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผํ๋ค.
struct ChecklistToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
// Return a view that has checklist appearance and behavior.
}
}
2) ์ํ๋ ๋ชจ์์ ํ ๊ธ๋ฒํผ view๋ฅผ ๋ฃ์ด์ค๋ค
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
Button(action: {
configuration.isOn.toggle()
}, label: {
VStack(alignment: .leading, spacing: 0){
HStack {
Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle")
.imageScale(.large)
configuration.label
.foregroundColor(.black)
}
.padding(5)
}
})
}
}
3) ๊ทธ๋ฆฌ๊ณ ์ค์ง์ ์ผ๋ก ํด๋น ์คํ์ผ์ ์ฌ์ฉํ ๋๋ ์ด๋ ๊ฒ toggleStyle์ ๋๊ฒจ์ฃผ๋ฉด๋๋ค.
import SwiftUI
struct ToggleStylePracticeView: View {
@State var isOn = false
var body: some View {
VStack {
Toggle(isOn: self.$isOn) {
Text("Toggle: \(String(self.isOn))")
}
.toggleStyle(CheckboxToggleStyle())
}
}
}
# ๐ฅจ ๋ณด๋ค ๋ ํ์ฅ ๊ฐ๋ฅํ custom toggle style ๋ง๋ค๊ธฐ
์ฑ์์ ์ ๋ชจ์, ์ฌ๊ฐํ ๋ชจ์ ๋ฑ์ ์ฒดํฌ๋ฐ์ค๊ฐ ์์ ๋, ์ฐ๋ฆฌ๋ ์๋์ ๊ฐ์ด ์ด๊ฑฐํ (enum)์ ์ฌ์ฉํ์ฌ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก ๋ง๋ค์ด์ค ์ ์๊ณ ,
struct CheckboxToggleStyle: ToggleStyle {
let style: Style
func makeBody(configuration: Configuration) -> some View {
Button(action: {
configuration.isOn.toggle()
}, label: {
VStack(alignment: .leading, spacing: 0){
HStack {
Image(systemName: configuration.isOn ? "checkmark.\(style.sfSymbolName).fill" : style.sfSymbolName)
.imageScale(.large)
configuration.label
.foregroundColor(.black)
}
.padding(5)
}
})
}
enum Style {
case square, circle
var sfSymbolName: String {
switch self {
case .square:
return "square"
case .circle:
return "circle"
}
}
}
}
์ค๋ณต ์ ํ ๊ฐ๋ฅํ ์ฒดํฌ ๋ฆฌ์คํธ ๋ฑ ์ฌ๋ฌ๊ฐ์ง ํํ์ ํ ๊ธ, ์ฒดํฌ๋ฐ์ค๋ฅผ ๊ตฌํํด์ผํ ๋๋ ์กฐ๊ธ์ ๋ก์ง๋ง ์ถ๊ฐํด์ค๋ค๋ฉด ์ด๋ ต์ง ์๊ฒ ๊ธฐ์กด์ ๋ง๋ค์ด๋ ์ปค์คํ ์คํ์ผ์ ์ฌ์ฌ์ฉํด์ค ์ ์๋ค.
import SwiftUI
struct MyTag {
let label : String
let value : Int
}
struct ToggleStylePracticeView: View {
@State var selectedTopics : [String] = ["tag1", "tag3"]
let myTags : [MyTag] = [
MyTag(label: "tag1", value: 1),
MyTag(label: "tag2", value: 2),
MyTag(label: "tag3", value: 3),
MyTag(label: "tag4", value: 4),
MyTag(label: "tag5", value: 5),
]
func binding(for key: String) -> Binding<Bool> {
return Binding(
get: {
return self.selectedTopics.contains(key)
}
, set: {
if($0 == false){
self.selectedTopics = self.selectedTopics.filter{topic in topic != key}
} else{
self.selectedTopics.append(key)
}
}
)
}
var body: some View {
VStack{
ForEach(myTags.map{$0.label}, id : \.self){el in
HStack{
Toggle(el, isOn: binding(for:el))
.toggleStyle(CheckboxToggleStyle(style: .circle))
.foregroundColor(.green)
Spacer()
}
}
}
}
}