포스트

WidgetKit (15)

CleanShot 2024-12-11 at 02 37 24

이렇게 SwiftCal 앱의 LockScreen을 디자인한다.

이번에 적용할 프로젝트는 CoreData Version으로 된 걸 사용했다.

EntryView를 각 Case 별로 분류

우선 환경변수 @Environment(\.widgetFamily) var family를 만들어 준다.

Widget의 Supported Family 수정

LockScreen의 위젯을 지원해야 하므로

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct SwiftCalWidget: Widget {
    let kind: String = "SwiftCalWidget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            // 생략
        }
        .configurationDisplayName("Swift Study Calendar")
        .description("Track days you study Swift with streaks.")
        .supportedFamilies([.systemMedium,
                            .accessoryRectangular,
                            .accessoryInline,
                            .accessoryCircular])
    }
}

이렇게 추가를 해준다.

MediumCalendarView 만들기

Widget 밑에 새로

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
private struct MediumCalendarView: View {
    var entry: CalendarEntry
    let columns = Array(repeating: GridItem(.flexible()), count: 7)
    var streakValue: Int

    var body: some View {
        HStack {
            Link(destination: URL(string: "streak")!) {
                VStack {
                    Text("\(streakValue)") // modified
                    // 생략
                }
            }
            
            Link(destination: URL(string: "calendar")!) {
                VStack {
                    CalendarHeaderView(font: .caption)
                    LazyVGrid(columns: columns, spacing: 7) {
                        // 생략
                    }
                }
            }
            .padding(.leading, 6)
        }
        .padding()
    }
}

위와 같이 필요한 View를 만들어준다. 이유는 각 case 별로 view를 나눌때 조금 더 EntryView의 코드를 간결하게 하기 위함이다.

LockScreenCircularView 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private struct LockScreenCircularView: View {
    var entry: CalendarEntry
    
    var currentCalendarDays: Int {
        entry.days.filter { $0.date?.monthInt == Date().monthInt }.count
    }
    
    var daysStudied: Int {
        entry.days.filter { $0.date?.monthInt == Date().monthInt }.filter { $0.didStudy }.count
    }
    
    var body: some View {
        Gauge(value: Double(daysStudied), in: 1...Double(currentCalendarDays)) {
            Image(systemName: "swift")
        } currentValueLabel: {
            Text("15")
        }
        .gaugeStyle(.accessoryCircular)

    }
}

Circular 특성을 활용한 Gauge 스타일은 진행 상황(예: 학습일)을 시각적으로 표현하는 데 적합하다.

Docs에 설명이 잘 나와있으므로 읽어보는걸 추천.

LockScreenRectangularView 만들기

MediumCalendarView와 유사하다.

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
private struct LockScreenRectangularView: View {
    var entry: CalendarEntry
    let columns = Array(repeating: GridItem(.flexible()), count: 7)
    
    var body: some View {
        LazyVGrid(columns: columns, spacing: 4) {
            ForEach(entry.days) { day in
                if day.date!.monthInt != Date().monthInt {
                    Text(" ")
                        .font(.system(size: 7))
                } else {
                    if day.didStudy {
                        Image(systemName: "swift")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 7, height: 7)
                    } else {
                        Text(day.date!.formatted(.dateTime.day()))
                            .font(.system(size: 7))
                            .frame(maxWidth: .infinity)                        
                    }
                }
            }
        }
        .padding()
    }
}

Case 별 View 적용

CleanShot 2024-12-11 at 07 32 12

테스트는 이렇게 8,9,10일을 공부했다고 가정하여 진행

inline

1
2
case .accessoryInline:
    Label("Streak - \(calculateStreakValue()) days", systemImage: "swift")

CleanShot 2024-12-11 at 07 33 27

Circular

1
2
case .accessoryCircular:
    LockScreenCircularView(entry: entry)

CleanShot 2024-12-11 at 07 32 04

Rectangular

1
2
case .accessoryRectangular:
    LockScreenRectangularView(entry: entry)

CleanShot 2024-12-11 at 07 44 38

Lock Screen 위젯에서 탭 이벤트 처리하기

1
2
3
case .accessoryInline:
    Label("Streak - \(calculateStreakValue()) days", systemImage: "swift")
        .widgetURL(URL(string: "streak"))

이미 SwiftCalApp.swift에서

1
2
3
.onOpenURL { url in
    selectedTab = url.absoluteString == "calendar" ? 0 : 1
}

적용중이기에 inline 쪽을 클릭하면 streakView가 나오게 된다.

Dec-11-2024 07-49-45

SwiftCal Lock Screen Padding (iOS 17)

LockScreenRectangularView의 LazyVGrid의 Padding을 지워주면 된다.

이로인해 Calender가 조금 더 확장되고 덜 비좁아지게 된다.

simulator_screenshot_5D4DB01F-C197-48B0-ADE2-742419B0D1BAsimulator_screenshot_274A6A7E-5416-49EA-A208-C073B1D1E491

padding을 삭제한것으로 좌(before), 우(after) 화면에서의 Calendar의 차이가 극명하게 보이는걸 알 수 있다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.