iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0

最後幾天,我想要優化首頁的功能,讓它顯示當前月份即將到期的物品。所以我們需要在首頁上方的導覽列中,加入年份和月份的選擇功能。今天,我們將實作首頁上方的月份顯示功能,並且在點擊月份按鈕後,彈出自定義視窗,讓使用者能選擇特定的年份和月份。此功能將使使用者能夠快速切換至不同月份,接下來我們會繼續實作這個月份選擇器的具體邏輯。

目標

  • 在首頁的導覽列中顯示當前月份按鈕。
  • 點擊按鈕後彈出自定義的月份選擇器。
  • 使用者選擇月份後,更新顯示月份並回傳選擇結果。

https://ooorito.com/wp-content/uploads/2024/10/%E7%9B%AE%E6%A8%99%E7%A4%BA%E6%84%8F%E5%9C%96.webp

主要實作

實作自訂義 YearMonthPicker

YearMonthPicker 是自定義的月份選擇器,使用者可以通過此選擇器快速切換年份和月份。

建立 YearMonthPicker 並設置月份顯示

首先,建立一個 YearMonthPicker 結構,通過 @Binding 來管理所選日期和彈窗的顯示狀態。使用 Calendar.current.shortMonthSymbols 提供月份的顯示,並用 LazyVGridGridItem 將月份顯示成網格排列。

struct YearMonthPicker: View {
    @Binding var selectedDate: Date
    @Binding var isShowing: Bool
    let months: [String] = Calendar.current.shortMonthSymbols
    let columns = [GridItem(.adaptive(minimum: 80))]

ZStack 背景和點擊處理

使用 ZStack 來包裝背景及彈窗內容。當彈窗顯示時,點擊背景的空白區域可以關閉彈窗。

ZStack {
    if isShowing {
        Rectangle()
            .background(Color(.systemBackground))
            .opacity(0.3)
            .ignoresSafeArea()
            .onTapGesture {
                isShowing.toggle()
            }

實作年份選擇功能

HStack 顯示年份,並在左右兩側加上 chevron.left 和 chevron.right 圖示,讓使用者點擊來切換年份。

HStack {
    Image(systemName: "chevron.left")
        .frame(width: 24.0)
        .onTapGesture {
            var dateComponent = DateComponents()
            dateComponent.year = -1
            selectedDate = Calendar.current.date(byAdding: dateComponent, to: selectedDate)!
        }
    Spacer()
    Text(selectedDate, formatter: formatter(type: "year"))
        .fontWeight(.bold)
    Spacer()
    Image(systemName: "chevron.right")
        .frame(width: 24.0)
        .onTapGesture {
            var dateComponent = DateComponents()
            dateComponent.year = 1
            selectedDate = Calendar.current.date(byAdding: dateComponent, to: selectedDate)!
        }
}

實作月份選擇功能

使用 LazyVGrid 將月份排列為網格顯示。當用戶點擊某個月份時,更新 selectedDate,並讓選中的月份背景顯示不同顏色。

LazyVGrid(columns: columns, spacing: 20) {
    ForEach(months, id: \.self) { item in
        Text(item)
            .font(.headline)
            .frame(width: 60, height: 33)
            .background(item == formatter(type: "month").string(from: selectedDate) ?  Color("AccentColor") : Color("BgColor"))
            .cornerRadius(8)
            .onTapGesture {
                var dateComponent = DateComponents(year: Int(formatter(type: "year").string(from: selectedDate)), month: months.firstIndex(of: item)! + 1, day: 1)
                selectedDate = Calendar.current.date(from: dateComponent)!
            }
    }
}

日期格式化功能

使用 DateFormatter 格式化顯示年份或月份,根據不同的參數來調整輸出的格式。

func formatter(type: String) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.dateFormat = type == "year" ? "yyyy" : "MMM"
    return formatter
}

修改 HomeView

最後,在 HomeView 中使用 YearMonthPicker,並用 @State 管理 selectedDate 和彈窗顯示的狀態。點擊上方的月份按鈕,顯示彈窗進行年月選擇。

@State private var isShowDatePicker = false

var body: some View {
            // 略...
            YearMonthPicker(selectedDate: $viewModel.selectedDate, isShowing: $isShowDatePicker)
            // 略...
                .toolbar {
                    ToolbarItem(placement: .principal) {
                        Button(action: {
                            self.isShowDatePicker.toggle()
                        }) {
                            Text(dateFormatter.string(from: viewModel.selectedDate))
                                .font(.headline)
                                .foregroundColor(Color("FontColor"))
                        }
                    }
            // 略...
}

private var dateFormatter: DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale.current
    if formatter.locale.identifier.contains("zh") {
        formatter.dateFormat = "yyyy年 MMM"
    } else {
        formatter.dateFormat = "yyyy MMM"
    }
    return formatter
}

https://ooorito.com/wp-content/uploads/2024/10/%E6%88%90%E6%9E%9C.gif

總結

今天實作導覽列月份顯示功能,並且為此新增了一個自定義的月份選擇器。透過 YearMonthPicker,使用者可以輕鬆地切換年份和月份,並在首頁上更新選擇的月份。明天我們將在首頁新增提示到期物品的區塊,明天見囉~

參考資料:Create custom month & year date picker in SwiftUI • Location Tracking Apps for iOS & Android


上一篇
Day 27: SwiftUI Dependency Injection
下一篇
Day 29: SwiftUI 實作到期物品提示功能
系列文
用 SwiftUI 掌控家庭日用品庫存30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言