4
3

More than 1 year has passed since last update.

【SwiftUI】DatePickerのカレンダーをボタンで表示させる方法

Posted at

はじめに

DatePickerのカレンダーを表示できるボタンを作りたく、実装方法を調べてみました。

環境

Xcode 14.1

内容

struct DatePicker<Label> where Label : View

DatePickerの使い方

DatePickerを使うことでカレンダーから日付を選択できる

@State private var date = Date()

var body: some View {
    DatePicker(
        "Start Date",
        selection: $date,
        displayedComponents: [.date]
    )
}

カレンダーから選択可能な期間を指定する場合は、ClosedRange<Date>を使う

@State private var date = Date()
let dateRange: ClosedRange<Date> = {
    let calendar = Calendar.current
    let startComponents = DateComponents(year: 2021, month: 1, day: 1)
    let endComponents = DateComponents(year: 2021, month: 12, day: 31, hour: 23, minute: 59, second: 59)
    return calendar.date(from:startComponents)!
        ...
        calendar.date(from:endComponents)!
}()

var body: some View {
    DatePicker(
        "Start Date",
         selection: $date,
         in: dateRange,
         displayedComponents: [.date, .hourAndMinute]
    )
}

datePickerStyle(_:)を使うことで、表示方法を変えられる

@State private var date = Date()

var body: some View {
    DatePicker(
        "Start Date",
        selection: $date,
        displayedComponents: [.date, .hourAndMinute]
    )
    .datePickerStyle(.compact)
}
.compact .wheel .graphical

カレンダーの表示ができるButton①

実装
struct CustomCalendarButtonView: View {
    @State var showDatePicker: Bool = false
    @State var savedDate: Date? = nil
    
    var body: some View {
        ZStack {
            HStack {
                Button {
                    showDatePicker.toggle()
                } label: {
                    Text("カレンダーを表示")
                    Image(systemName: "calendar")
                }
                .buttonStyle(.bordered)
            }
            if showDatePicker {
                CustomDatePicker(
                    showDatePicker: $showDatePicker,
                    savedDate: $savedDate,
                    selectedDate: savedDate ?? Date()
                )
                .animation(.linear, value: savedDate)
                .transition(.opacity)
            }
        }
        
    }
}

struct CustomDatePicker: View {
    @Binding var showDatePicker: Bool
    @Binding var savedDate: Date?
    @State var selectedDate: Date = Date()
    
    var body: some View {
        ZStack {
            Color.black.opacity(0.3)
                .edgesIgnoringSafeArea(.all)
                .onTapGesture {
                    showDatePicker = false
                }
            VStack {
                DatePicker(
                    "",
                    selection: $selectedDate,
                    displayedComponents: [.date, .hourAndMinute]
                )
                .datePickerStyle(.graphical)
                Divider()
                HStack {
                    Button("キャンセル") {
                        showDatePicker = false
                    }
                    Spacer()
                    Button("保存") {
                        savedDate = selectedDate
                        showDatePicker = false
                    }
                }
                .padding(.vertical, 15)
                .padding(.horizontal, 10)
            }
            .padding(.horizontal, 20)
            .background(
                Color.white
                    .cornerRadius(30)
            )
            .padding(.horizontal, 20)
        }
    }
}

カレンダーの表示ができるButton②

実装
    @State var showDatePicker = false
    @State var date = Date()
    
    var body: some View {
        VStack {
            Button {
                showDatePicker.toggle()
            } label: {
                Text("カレンダーを表示")
                Image(systemName: "calendar")
            }
            .buttonStyle(.bordered)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .overlay {
            ZStack{
                if showDatePicker {
                    Color.black.opacity(0.3)
                        .edgesIgnoringSafeArea(.all)
                        .onTapGesture {
                            showDatePicker = false
                        }
                    DatePicker(
                        "",
                        selection: $date,
                        displayedComponents: [.date, .hourAndMinute]
                    )
                    .datePickerStyle(.graphical)
                    .padding()
                    .background(.white, in: RoundedRectangle(
                        cornerRadius: 10,
                        style: .continuous)
                    )
                    .padding()
                }
            }
            .animation(.default, value: showDatePicker)
        }
    }

複数選択のできるカレンダーの表示

MultiDatePickerを使うことで複数日が選択できるカレンダーが表示できる

struct MultiDatePicker<Label> where Label : View

実装
    @State var showDatePicker = false
    @State private var dates: Set<DateComponents> = []
    
    var body: some View {
        VStack {
            Button {
                showDatePicker.toggle()
            } label: {
                Text("カレンダーを表示")
                Image(systemName: "calendar")
            }
            .buttonStyle(.bordered)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .overlay {
            ZStack{
                if showDatePicker {
                    Color.black.opacity(0.3)
                        .edgesIgnoringSafeArea(.all)
                        .onTapGesture {
                            showDatePicker = false
                        }
                    MultiDatePicker(selection: $dates) {
                        Text("")
                    }
                    .datePickerStyle(.graphical)
                    .padding()
                    .background(.white, in: RoundedRectangle(
                        cornerRadius: 10,
                        style: .continuous)
                    )
                    .padding()
                }
            }
            .animation(.default, value: showDatePicker)
        }
    }

おわりに

参考記事に助けられながら、実装したいものができました!
それと、MultiDatePickerがiOS16から使えるようになったようですね

参考

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3