728x90
Add a theme view
import SwiftUI
import ThemeKit
struct ThemeView: View {
let theme : Theme
var body: some View {
Text(theme.name)
.padding(4)
.frame(maxWidth: .infinity) //Make the text view span the width of the parent view
.background(theme.mainColor)
.foregroundColor(theme.accentColor) //mainColor와의 대비를 최대로 하기 위해 검정 또는 흰색을 반환하게 된다.
.clipShape(RoundedRectangle(cornerRadius: 4))
}
}
#Preview {
ThemeView(theme: .lavender)
}
Add a theme picker
import SwiftUI
import ThemeKit
struct ThemePicker: View {
@Binding var selection: Theme
var body: some View {
Picker("테마컬러", selection: $selection) {
ForEach(Theme.allCases) { theme in
ThemeView(theme: theme)
.tag(theme)
}
}
.pickerStyle(.navigationLink)
}
}
#Preview {
@Previewable @State var theme = Theme.seafoam
//Previewable variables are useful for prototyping your app’s user interface.
ThemePicker(selection: $theme)
}
Pass the edit view a binding to data

여기서 여기저기 바뀐게 많은데, 알아둘점은
@State 선언 후 여기저기 하위 뷰들에서 @Binding 받아서 가져다쓰면 된다는 것이다.
바뀐 부분은 데이터를 주고받는 부분들인데, 일단 전체 코드 첨부!!
import SwiftUI
struct DetailEditView: View {
@Binding var scrum: DailyScrum // 상위 뷰에서 받는 값
// @State private var scrum = DailyScrum.emptyScrum
@State private var attendeeName = "" // input 받을 참석자명
var body: some View {
Form {
Section(header: Text("Meeting Info")) {
TextField("회의명", text: $scrum.title)
/**
TextField takes a binding to a String. You can use the $ syntax to create a binding to scrum.title. The current view manages the state of the data property.
*/
HStack {
Slider(value: $scrum.lengthInMinutesAsDouble, in: 5...30, step: 1) {
Text("Length")
//the slider and the label stay in sync.
}
.accessibilityValue("\(scrum.lengthInMinutes) minutes") // 접근성
Spacer()
Text("\(scrum.lengthInMinutes) minutes")
.accessibilityValue("\(scrum.lengthInMinutes) minutes")
.accessibilityHidden(true) //중복이므로 hidden
}
ThemePicker(selection: $scrum.theme)
}
Section(header: Text("참석자 목록")) {
ForEach(scrum.attendees) { attendee in
Text(attendee.name)
}
.onDelete { indices in
scrum.attendees.remove(atOffsets: indices)
//onDelete when the user swipes to delete a row
}
HStack {
TextField("새로운 참석자", text: $attendeeName)
Button(action: {
withAnimation {
//setting the value to the empty string also clears the contents of the text field.
let attendee = DailyScrum.Attendee(name: attendeeName)
scrum.attendees.append(attendee)
// binding to attendeeName, setting the value to the empty string also clears the contents of the text field
// animation block 안에서 처리!
attendeeName = ""
}
}) {
Image(systemName: "plus.circle.fill")
.accessibilityLabel("참석자 추가")
}
.disabled(attendeeName.isEmpty)
}
}
}
}
}
#Preview {
@Previewable @State var scrum = DailyScrum.sampleData[0]
DetailEditView(scrum: $scrum)
}
import SwiftUI
struct DetailView: View {
// let scrum: DailyScrum
@Binding var scrum: DailyScrum // binding 받아서 보여준다.
@State private var isPresentingEditView = false //add a Boolean @State property named isPresentingEditView.
@State private var editingScrum = DailyScrum.emptyScrum
var body: some View {
List {
Section(header: Text("Meeting Info")) {
// Label("Start Meeting", systemImage: "timer")
// .font(.headline)
// .foregroundColor(.accentColor)
// 3depth
NavigationLink(destination: MeetingView()) {
Label("Start Meeting", systemImage: "timer")
.font(.headline)
.foregroundColor(.accentColor)
}
HStack {
Label("Length", systemImage: "clock")
Spacer()
Text("\(scrum.lengthInMinutes) minutes")
}
.accessibilityElement(children: .combine)
/**
VoiceOver 사용 시 설정
.accessibilityElement
.accessibilityLabel("내 맘대로 정의") // 사용자가 정의한 라벨 적용
SwiftUI에서 접근성(VoiceOver 등)이 특정 UI 요소를 어떻게 인식할지 정의
.ignore : 접근성 요소로 인식하지 않음
.combine : 하나의 요소로 읽음
.contain : 개별로 읽음
*/
HStack {
Label("Theme", systemImage: "paintpalette")
Spacer()
Text(scrum.theme.name)
.padding(4)
.foregroundColor(scrum.theme.accentColor)
.background(scrum.theme.mainColor)
.cornerRadius(4)
}
.accessibilityElement(children: .combine)
}
// 참석자
Section(header: Text("Attendees")) {
ForEach(scrum.attendees) { attendee in
Label(attendee.name, systemImage: "person")
}
}
}
.navigationTitle(scrum.title)
.toolbar {
Button("수정") {
isPresentingEditView = true
}
}
.sheet(isPresented: $isPresentingEditView) {
NavigationStack{
DetailEditView(scrum: $editingScrum)// 3depth
// sheet 에 보여질 내용들을 아래에 구성한다
.navigationTitle(scrum.title)
.toolbar{
ToolbarItem(placement: .cancellationAction) {
Button("취소") {
isPresentingEditView = false
}
}
ToolbarItem(placement: .confirmationAction) {
Button("저장") {
isPresentingEditView = false
}
}
}
}
}
}
}
#Preview {
//Wrap DetailView in a NavigationStack to preview navigation elements on the canvas.
// NavigationStack {
// DetailView(scrum: DailyScrum.sampleData[0])
// }
@Previewable @State var scrum = DailyScrum.sampleData[0]
NavigationStack {
DetailView(scrum: $scrum)
}
}
import SwiftUI
struct ScrumsView: View {
// let scrums: [DailyScrum]
@Binding var scrums: [DailyScrum]
var body: some View {
// Identifiable protocol, you can simplify the List initializer.
// List(scrums) { scrum in
// CardView(scrum: scrum)
// .listRowBackground(scrum.theme.mainColor)
// }
// NavigationStack
NavigationStack {
List($scrums) { $scrum in
NavigationLink(destination: DetailView(scrum: $scrum)) {
//Pass a Binding<DailyScrum> to the DetailView initializer.
CardView(scrum: scrum)
}
.listRowBackground(scrum.theme.mainColor)
}
.navigationTitle("Daily Scrums")
.toolbar {
//Pass an empty action to the button for now.
Button(action: {}) {
Image(systemName: "plus")
}
.accessibilityLabel("New Scrum")
}
}
}
}
#Preview {
// ScrumsView(scrums: DailyScrum.sampleData)
@Previewable @State var scrums = DailyScrum.sampleData
ScrumsView(scrums: $scrums)
}
@main
struct ScrumdingerApp: App {
//add a private @State property named scrums.
@State private var scrums = DailyScrum.sampleData
var body: some Scene {
WindowGroup {
ScrumsView(scrums: $scrums)
}
}
}
728x90
'iOS > App' 카테고리의 다른 글
Scrumdinger 개발 06 : Updating app data (0) | 2025.04.06 |
---|---|
Scrumdinger 개발 05 - Managing state and life cycle (0) | 2025.04.05 |
Scrumdinger 개발 03 - Managing data flow between views ~ Creating the edit view (0) | 2025.04.02 |
Scrumdinger 개발 02 - Creating a navigation hierarchy (0) | 2025.04.01 |
Scrumdinger 개발 01 - Displaying data in a list (0) | 2025.03.31 |