宿å
æ è¡ã®ã¹ã±ãžã¥ãŒã«èšç»ã»ç®¡çã¢ããª
ãããªæãã
â»âã®ãšã©ãŒãåºãŠããŸãâŠä¿®æ£ã§ããäžæŠå€±ç€ŒããŸãã
æ©èœ
- æ
è¡ã®ç®¡ç
- ãŠãŒã¶ãŒã¯æ°ããæ è¡ãäœæããæ è¡ã®ã¿ã€ãã«ãšæ¥ä»ç¯å²ãèšå®ã§ããŸãã
- æ¢åã®æ è¡ãéžæããŠããã®æ è¡ã«é¢é£ããã¹ã±ãžã¥ãŒã«ã管çã§ããŸãã
- ã¹ã±ãžã¥ãŒã«ã®è¿œå ãšç®¡ç
- åæ è¡ã«å¯ŸããŠãæ¥ä»ããšã«ã¹ã±ãžã¥ãŒã«ã远å ã§ããŸãã
- ã¹ã±ãžã¥ãŒã«ã«ã¯ã¿ã€ãã«ãã¡ã¢ããžã£ã³ã«ïŒç§»åããã¯ãã芳å ãããã«ïŒãèšå®ã§ããŸãã
- ã¹ã±ãžã¥ãŒã«ã®éå§æéãšçµäºæéãèšå®ããæéã®ã·ã§ãŒãã«ãããã¿ã³ã䜿çšããŠç°¡åã«æéã調æŽã§ããŸãã
- ã¹ã±ãžã¥ãŒã«ã®åé€
- ã¹ã±ãžã¥ãŒã«ãåé€ããããã®æ©èœããããåé€åã«ç¢ºèªã®ã¢ã©ãŒãã衚瀺ãããŸãã
- æ€çŽ¢æ©èœ
- æ è¡ã¿ã€ãã«ãæ€çŽ¢ããŠãç¹å®ã®æ è¡ãçŽ æ©ãèŠã€ããããšãã§ããŸãã
UI
- ããã²ãŒã·ã§ã³ãšã¿ããã¥ãŒ
- NavigationViewãšTabViewã䜿çšããŠããŠãŒã¶ãŒãç°¡åã«ç°ãªããã¥ãŒéãç§»åã§ããããã«ããŠããŸãã
- ããã«ãŒãšãªã¹ã
- Pickerã䜿çšããŠæ è¡ãéžæããListã䜿çšããŠã¹ã±ãžã¥ãŒã«ãæ¥ä»ããšã«è¡šç€ºããŸãã
- ã¢ãŒãã«ã·ãŒã
- æ°ããæ è¡ãäœæããããã®ã·ãŒãã衚瀺ããããŠãŒã¶ãŒã¯æ è¡ã®è©³çްãå ¥åã§ããŸãã
- ã¢ã©ãŒã
- å ¥åãšã©ãŒãåé€ç¢ºèªã®ããã®ã¢ã©ãŒããéç¥ããŸãã
- ã¬ã¹ãã³ã·ããã¶ã€ã³
- VStackãHStackã䜿çšããŠãæ§ã ãªããã€ã¹ãµã€ãºã«é©å¿ããããã«èšèšããŠããŸãã
äœæã®èæ¯
- 以äžã®èšäºãèªã¿ã圱é¿ãããããšã倧ããã§ãã
- çŽè¿1幎éPythonã®åŠç¿ãé²ããŠããŸããããä»åŸããã«èªåã®ã¹ãã«ã®å¹ ãåºããããä»ã®ããã°ã©ãã³ã°èšèªãåŠç¿ããŠãããããšæã£ãŠããŸããã
- ãããŠããã®æ©äŒã«ã©ãããªããããŸã§ã«å šãè§Šã£ãããšã®ãªãSwiftã«ãã£ã¬ã³ãžããããšæããŸãããïŒããããã°ã¢ããªãå ¬éããããšæã£ãŠããã®ã§ãããä»ã®ãšããäºå®ã¯ãããŸãããïŒ
- 1é±éçšåºŠãSwiftã«é¢ããç¥èãQiitaèšäºãYoutubeã§ã€ã³ãããããã®ã¡ã«ãGPTãªã©ã䜿ããªãããæ¬ã¢ããªãéçºããŠããŸãã
䜿çšããŒã«
- Xcode
- iPhone14 (éçºè ã¢ãŒãããªã³)
ã³ãŒã
以äžãã³ãŒãå šæã§ãã
å®éã®ã³ãŒããŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒãŒ
import SwiftUI
// Scheduleåã®å®çŸ©
struct Schedule: Identifiable, Hashable {
let id = UUID()
var title: String
var memo: String
var genre: String // ãžã£ã³ã«ã远å
init(title: String, memo: String, genre: String) {
self.title = title
self.memo = memo
self.genre = genre
}
// ãžã£ã³ã«ã«åºã¥ãçµµæåãè²ãè¿ã
var emoji: String {
switch genre {
case "ðç§»å": return "ð"
case "ðœãã¯ã": return "ðœ"
case "ð芳å
": return "ð"
case "ðšããã«": return "ðš"
default: return "â"
}
}
}
// MainViewã®å®çŸ©
struct MainView: View {
@Binding var trips: [String: [String: [Schedule]]]
@Binding var selectedTrip: String
var body: some View {
NavigationView {
TabView {
ContentView(trips: $trips, selectedTrip: $selectedTrip)
.tabItem {
Label(selectedTrip.isEmpty ? "æ
è¡" : selectedTrip, systemImage: "airplane")
}
}
}
}
}
// ContentViewã®å®çŸ©
struct ContentView: View {
@Binding var trips: [String: [String: [Schedule]]]
@Binding var selectedTrip: String
@State private var newTripName = ""
@State private var showNewTripSheet = false
@State private var departureDate = Date()
@State private var returnDate = Date()
@State private var selectedDate = Date()
@State private var startTime = Date()
@State private var endTime = Date()
@State private var newSchedule = ""
@State private var newMemo = ""
@State private var showAlert = false
@State private var alertMessage = ""
@State private var scheduleToDelete: (String, IndexSet)? = nil
@State private var searchText = ""
var filteredTrips: [String] {
if searchText.isEmpty {
return Array(trips.keys)
} else {
return trips.keys.filter { $0.contains(searchText) }
}
}
var body: some View {
NavigationView {
VStack {
TextField("æ€çŽ¢", text: $searchText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
TripPicker(trips: $trips, selectedTrip: $selectedTrip, showNewTripSheet: $showNewTripSheet, filteredTrips: filteredTrips)
if let dates = trips[selectedTrip] {
ScheduleListView(dates: dates, selectedTrip: $selectedTrip, trips: $trips, showAlert: $showAlert, scheduleToDelete: $scheduleToDelete)
} else {
Text("æ
è¡ãéžæãŸãã¯äœæããŠãã ãã")
.padding()
}
if !selectedTrip.isEmpty && trips[selectedTrip] != nil {
ScheduleInputView(selectedDate: $selectedDate, departureDate: $departureDate, returnDate: $returnDate, startTime: $startTime, endTime: $endTime, newSchedule: $newSchedule, newMemo: $newMemo, trips: $trips, selectedTrip: $selectedTrip, alertMessage: $alertMessage, showAlert: $showAlert)
}
}
.navigationTitle("æ
è¡ã¹ã±ãžã¥ãŒã«äžèЧ")
.toolbar {
ToolbarItem {
Button(action: {
showNewTripSheet = true
}) {
Text("æ°ããæ
è¡ãäœæ")
}
}
ToolbarItem {
Button(action: {
if !selectedTrip.isEmpty {
trips.removeValue(forKey: selectedTrip)
selectedTrip = trips.keys.first ?? ""
}
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
}
}
.sheet(isPresented: $showNewTripSheet) {
NewTripSheet(trips: $trips, newTripName: $newTripName, departureDate: $departureDate, returnDate: $returnDate, selectedTrip: $selectedTrip, showNewTripSheet: $showNewTripSheet, alertMessage: $alertMessage, showAlert: $showAlert)
}
.alert(isPresented: $showAlert) {
Alert(
title: Text("å
¥åãšã©ãŒ"),
message: Text(alertMessage),
dismissButton: .default(Text("OK"))
)
}
}
}
}
// TripPickerã®å®çŸ©
struct TripPicker: View {
@Binding var trips: [String: [String: [Schedule]]]
@Binding var selectedTrip: String
@Binding var showNewTripSheet: Bool
var filteredTrips: [String]
var body: some View {
if !filteredTrips.isEmpty {
Picker("æ
è¡ãéžæ", selection: $selectedTrip) {
ForEach(filteredTrips, id: \.self) { trip in
Text(trip).tag(trip)
}
}
.pickerStyle(MenuPickerStyle())
.padding()
.onChange(of: selectedTrip) { newValue in
if newValue == "æ°ããæ
è¡ãäœæ" {
showNewTripSheet = true
selectedTrip = trips.keys.first ?? ""
}
}
}
}
}
struct ScheduleListView: View {
var dates: [String: [Schedule]]
@Binding var selectedTrip: String
@Binding var trips: [String: [String: [Schedule]]]
@Binding var showAlert: Bool
@Binding var scheduleToDelete: (String, IndexSet)?
var body: some View {
List {
ForEach(dates.keys.sorted(), id: \.self) { date in
Section(header: Text(date)) {
ForEach(dates[date] ?? [], id: \.self) { schedule in
HStack {
if let tripSchedules = trips[selectedTrip],
let daySchedules = tripSchedules[date],
let index = daySchedules.firstIndex(of: schedule) {
let binding = Binding<Schedule>(
get: { trips[selectedTrip]![date]![index] },
set: { trips[selectedTrip]![date]![index] = $0 }
)
NavigationLink(destination: DetailView(schedule: binding)) {
Text("\(schedule.emoji) \(schedule.title)")
}
}
Spacer()
Button(action: {
if let index = dates[date]?.firstIndex(of: schedule) {
scheduleToDelete = (date, IndexSet(integer: index))
showAlert = true
}
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
}
}
}
}
}
.alert(isPresented: $showAlert) {
Alert(
title: Text("åé€ç¢ºèª"),
message: Text("æ¬åœã«åé€ããŠããã§ããïŒ"),
primaryButton: .destructive(Text("åé€")) {
if let (date, indexSet) = scheduleToDelete {
deleteSchedule(date: date, at: indexSet)
}
},
secondaryButton: .cancel(Text("ãã£ã³ã»ã«"))
)
}
}
func deleteSchedule(date: String, at offsets: IndexSet) {
trips[selectedTrip]?[date]?.remove(atOffsets: offsets)
}
}
// ScheduleInputViewã®å®çŸ©
import SwiftUI
struct ScheduleInputView: View {
@Binding var selectedDate: Date
@Binding var departureDate: Date
@Binding var returnDate: Date
@Binding var startTime: Date
@Binding var endTime: Date
@Binding var newSchedule: String
@Binding var newMemo: String
@Binding var trips: [String: [String: [Schedule]]]
@Binding var selectedTrip: String
@Binding var alertMessage: String
@Binding var showAlert: Bool
@State private var selectedGenre = "ðç§»å"
@State private var isExpanded = false // ããã¯ãŒã®ç¶æ
let genres = ["ðç§»å", "ðœïžãã¯ã", "ðïžèгå
", "ðšããã«"]
var body: some View {
VStack {
ScrollView { // 瞊ã¹ã¯ããŒã«ãæå¹ã«
VStack(spacing: 20) {
if isExpanded {
VStack(spacing: 20) {
// éãããã¿ã³ãåžžã«äžã«è¡šç€º
HStack {
Spacer()
Button(action: {
isExpanded.toggle()
}) {
Text("éãã")
.foregroundColor(.blue)
}
}
.padding(.horizontal)
Picker("ãžã£ã³ã«ãéžæ", selection: $selectedGenre) {
ForEach(genres, id: \.self) { genre in
Text(genre).tag(genre)
}
}
.pickerStyle(SegmentedPickerStyle())
.padding()
TextField("ã¹ã±ãžã¥ãŒã«ã®ã¿ã€ãã«", text: $newSchedule)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal)
DatePicker("æ¥ä»ãéžæ", selection: $selectedDate, in: departureDate...returnDate, displayedComponents: .date)
.datePickerStyle(CompactDatePickerStyle())
.padding(.horizontal)
DatePicker("éå§æé", selection: $startTime, displayedComponents: .hourAndMinute)
.padding(.horizontal)
// çµäºæéã®ã·ã§ãŒãã«ãããã¿ã³ã«åºåãã远å
HStack(spacing: 10) {
ForEach([30, 60, 90, 120, 180], id: \.self) { minutes in
Button(action: {
endTime = Calendar.current.date(byAdding: .minute, value: minutes, to: startTime) ?? endTime
}) {
Text(minutes == 30 ? "30å" : "\(minutes / 60)æé\(minutes % 60 > 0 ? "å" : "")")
.frame(minWidth: 60)
.padding(5)
.background(Color.blue.opacity(0.2))
.cornerRadius(5)
}
}
}
.padding(.horizontal)
DatePicker("çµäºæé", selection: $endTime, displayedComponents: .hourAndMinute)
.padding(.horizontal)
TextField("ã¡ã¢ã远å ", text: $newMemo)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal)
Button(action: {
if !newSchedule.isEmpty {
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH:mm"
let schedule = Schedule(
title: "\(timeFormatter.string(from: startTime))~\(timeFormatter.string(from: endTime)) \(selectedGenre): \(newSchedule)",
memo: newMemo,
genre: selectedGenre
)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
let dateString = dateFormatter.string(from: selectedDate)
if trips[selectedTrip]?[dateString] != nil {
trips[selectedTrip]?[dateString]?.append(schedule)
} else {
trips[selectedTrip]?[dateString] = [schedule]
}
newSchedule = ""
newMemo = ""
alertMessage = ""
} else {
alertMessage = "ã¹ã±ãžã¥ãŒã«ãå
¥åããŠãã ããã"
showAlert = true
}
}) {
Text("ã¹ã±ãžã¥ãŒã«ã远å ")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.padding(.horizontal)
}
.padding(.top)
.background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.systemGray6)))
.padding()
}
}
.frame(maxWidth: .infinity) // ç»é¢å¹
ã«åãŸãããã«èª¿æŽ
}
// æ°ããã¹ã±ãžã¥ãŒã«ãã¿ã³ãç»é¢ã®æäžéšã«é
眮
Button(action: {
isExpanded.toggle()
}) {
Text("æ°ããã¹ã±ãžã¥ãŒã«")
.font(.headline)
.foregroundColor(.blue)
.padding()
.background(Color(UIColor.systemGray5))
.cornerRadius(10)
}
.padding()
}
}
}
// NewTripSheetã®å®çŸ©
struct NewTripSheet: View {
@Binding var trips: [String: [String: [Schedule]]]
@Binding var newTripName: String
@Binding var departureDate: Date
@Binding var returnDate: Date
@Binding var selectedTrip: String
@Binding var showNewTripSheet: Bool
@Binding var alertMessage: String
@Binding var showAlert: Bool
var body: some View {
VStack {
HStack {
Spacer()
Button(action: {
showNewTripSheet = false
}) {
Text("éãã")
.font(.caption)
.padding(5)
}
}
Text("æ°ããæ
è¡ã®ã¿ã€ãã«ãšæ¥ä»")
.font(.headline)
.padding()
TextField("æ°ããæ
è¡ã®ã¿ã€ãã«", text: $newTripName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Form {
DatePicker("åºçºæ¥", selection: $departureDate, in: Date()..., displayedComponents: .date)
.datePickerStyle(GraphicalDatePickerStyle())
.onAppear {
departureDate = Calendar.current.date(byAdding: .day, value: 1, to: Date()) ?? Date()
returnDate = departureDate
}
.onChange(of: departureDate) { newValue in
if returnDate < newValue {
returnDate = newValue
}
}
Text("éžæãããåºçºæ¥: \(formattedDate(departureDate))")
.padding(.bottom, 5)
DatePicker("åž°çæ¥", selection: $returnDate, in: departureDate..., displayedComponents: .date)
.datePickerStyle(GraphicalDatePickerStyle())
Text("éžæãããåž°çæ¥: \(formattedDate(returnDate))")
.padding(.bottom, 5)
}
Text("éžæãããæ¥ä»: \(formattedDateRange())")
.padding()
if !alertMessage.isEmpty {
Text(alertMessage)
.foregroundColor(.red)
.padding(.bottom, 5)
}
Button(action: {
guard !newTripName.isEmpty, departureDate <= returnDate else {
alertMessage = "æ
è¡ã®ã¿ã€ãã«ãå
¥åããŠãã ããã"
return
}
let dates = generateDateRange(from: departureDate, to: returnDate)
trips[newTripName] = [:]
for date in dates {
trips[newTripName]?[date] = []
}
selectedTrip = newTripName
newTripName = ""
showNewTripSheet = false
alertMessage = ""
}) {
Text("æ
è¡ã远å ")
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.shadow(radius: 5)
}
.padding()
}
.padding()
}
func formattedDate(_ date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
return dateFormatter.string(from: date)
}
func formattedDateRange() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
return "\(dateFormatter.string(from: departureDate)) - \(dateFormatter.string(from: returnDate))"
}
func generateDateRange(from startDate: Date, to endDate: Date) -> [String] {
var dates = [String]()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
var currentDate = startDate
while currentDate <= endDate {
dates.append(dateFormatter.string(from: currentDate))
currentDate = Calendar.current.date(byAdding: .day, value: 1, to: currentDate) ?? currentDate
}
return dates
}
}
struct DetailView: View {
@Binding var schedule: Schedule
var body: some View {
VStack {
Text("\(schedule.title) ã®è©³çް")
.font(.headline)
TextEditor(text: $schedule.memo)
.border(Color.gray, width: 1)
.padding()
}
.navigationTitle(schedule.title)
}
}
äž»ãªæ§é äœã»ãã¥ãŒçš®é¡
-
Scheduleæ§é äœ
- IdentifiableãšHashableãããã³ã«ã«æºæ ããã¹ã±ãžã¥ãŒã«ã®ã¿ã€ãã«ãã¡ã¢ããžã£ã³ã«ãä¿æ
- ãžã£ã³ã«ã«åºã¥ããŠçµµæåãè¿ãããããã£emoji
-
MainView
- NavigationViewãšTabViewã䜿çšããŠãã¢ããªã®ã¡ã€ã³ãã¥ãŒãæ§æ
- ContentViewãã¿ããšããŠè¡šç€º
-
ContentView
- æ è¡ã®ãªã¹ãã衚瀺ããæ°ããæ è¡ãäœæããããã®UIãæäŸ
- TripPickerã䜿çšããŠæ è¡ãéžæããScheduleListViewã§ã¹ã±ãžã¥ãŒã«ã衚瀺
- ScheduleInputViewã䜿çšããŠæ°ããã¹ã±ãžã¥ãŒã«ã远å
-
TripPicker
- æ è¡ãéžæããããã®ããã«ãŒãæäŸ
-
ScheduleListView
- éžæãããæ è¡ã®æ¥ä»ããšã«ã¹ã±ãžã¥ãŒã«ããªã¹ã衚瀺
- ã¹ã±ãžã¥ãŒã«ãåé€ããããã®ãã¿ã³ãæäŸ
-
ScheduleInputView
- æ°ããã¹ã±ãžã¥ãŒã«ãå ¥åããããã®ãã©ãŒã ãæäŸ
- ã¹ã±ãžã¥ãŒã«ã®ã¿ã€ãã«ãæ¥ä»ãéå§æéãçµäºæéãã¡ã¢ãå ¥åå¯èœ
-
NewTripSheet
- æ°ããæ è¡ãäœæããããã®ã·ãŒãã衚瀺
- æ è¡ã®ã¿ã€ãã«ãšæ¥ä»ç¯å²ãèšå®
-
DetailView
- ã¹ã±ãžã¥ãŒã«ã®è©³çްã衚瀺ããã¡ã¢ãç·šéããããã®ãã¥ãŒ
䜿çšããŠããäž»ãªswiftã³ãŒã
å ¥éã¬ãã«
- 倿°ãšå®æ°ã®å®çŸ©
letã¯å®æ°ãå®çŸ©ããããã«äœ¿çšãããäžåºŠå€ãèšå®ãããšå€æŽã§ããŸããã
varã¯å€æ°ãå®çŸ©ããå€ã倿Žã§ããŸã
let id = UUID() // äžæã®èå¥åãçæãã宿°
var title: String // 倿Žå¯èœãªæååããããã£
- æ§é äœã®å®çŸ©
structã¯ããŒã¿ããŸãšããããã®åºæ¬çãªæ¹æ³ã§ãã
ããããã£ãšã¡ãœãããæã€ããšãã§ããŸãã
Identifiableãããã³ã«ã¯ããªã¹ã衚瀺ãªã©ã§äžæã«èå¥ããããã«äœ¿çšãããŸãã
Hashableãããã³ã«ã¯ãã³ã¬ã¯ã·ã§ã³å ã§ã®éè€ãé¿ããããã«äœ¿çšãããŸãã
struct Schedule: Identifiable, Hashable {
let id = UUID()
var title: String
var memo: String
var genre: String
}
- åºæ¬çãªUIèŠçŽ :
Textã¯æååã衚瀺ããããã®ãã¥ãŒã§ãã
Buttonã¯ãŠãŒã¶ãŒãã¿ããã§ããã€ã³ã¿ã©ã¯ãã£ããªèŠçŽ ã§ãã
Text("æ°ããã¹ã±ãžã¥ãŒã«")
Button(action: {
// ã¢ã¯ã·ã§ã³
}) {
Text("ã¹ã±ãžã¥ãŒã«ã远å ")
}
åºæ¬ã¬ãã«
-
ãããã³ã«ã®äœ¿çš
ãããã³ã«ã¯ãç¹å®ã®æ©èœãæäŸããããã®å¥çŽã§ããIdentifiableãHashableã¯ãæ§é äœãç¹å®ã®æ©èœãæã€ããšãä¿èšŒããŸãã -
SwiftUIã®ãã¥ãŒæ§é
Viewãããã³ã«ã«æºæ ããããšã§ãã«ã¹ã¿ã ãã¥ãŒãäœæã§ããŸãã
bodyããããã£ã§ãã¥ãŒã®å 容ãå®çŸ©ããŸãã
struct MainView: View {
var body: some View {
NavigationView {
// ãã¥ãŒã®å
容
}
}
}
- ããŒã¿ãã€ã³ãã£ã³ã°
@'Bindingã¯ã芪ãã¥ãŒããæž¡ãããããŒã¿ãåãã¥ãŒã§äœ¿çšãã倿Žã芪ãã¥ãŒã«åæ ãããããã«äœ¿çšããŸãã
struct ContentView: View {
@Binding var trips: [String: [String: [Schedule]]]
// ãã¥ãŒã®å
容
}
- ç¶æ
管ç
@'Stateã¯ããã¥ãŒå ã§ã®äžæçãªç¶æ ã管çããããã«äœ¿çšããŸãããã¥ãŒãåæç»ããããšãã«ç¶æ ãä¿æãããŸãã
@State private var newTripName = ""
å¿çšã¬ãã«
- ãã¥ãŒã®çµã¿åãããšã¬ã€ã¢ãŠã
NavigationViewã¯ãéå±€çãªããã²ãŒã·ã§ã³ãæäŸããŸããTabViewã¯ãã¿ãã䜿ã£ãããã²ãŒã·ã§ã³ãæäŸããŸãã
NavigationView {
TabView {
ContentView(trips: $trips, selectedTrip: $selectedTrip)
.tabItem {
Label(selectedTrip.isEmpty ? "æ
è¡" : selectedTrip, systemImage: "airplane")
}
}
}
- ã«ã¹ã¿ã ãã¥ãŒã®äœæ:
è€æ°ã®ãã¥ãŒãçµã¿åãããŠåå©çšå¯èœãªã«ã¹ã¿ã ãã¥ãŒãäœæããŸããããã«ãããã³ãŒãã®åå©çšæ§ãåäžããŸãã
struct TripPicker: View {
@Binding var trips: [String: [String: [Schedule]]]
// ãã¥ãŒã®å
容
}
- æ¡ä»¶ä»ãããžãã¯ãšãã¥ãŒã®æŽæ°:
ifæã䜿ã£ãŠãæ¡ä»¶ã«å¿ããŠãã¥ãŒã衚瀺ããããæŽæ°ãããããŸãã
if !selectedTrip.isEmpty && trips[selectedTrip] != nil {
// ãã¥ãŒã®å
容
}
- ã¢ã©ãŒããšã·ãŒãã®äœ¿çš
Alertã¯ããŠãŒã¶ãŒã«éèŠãªæ å ±ãéç¥ããããã«äœ¿çšããŸããSheetã¯ãã¢ãŒãã«ãã¥ãŒã衚瀺ããããã«äœ¿çšããŸãã
.alert(isPresented: $showAlert) {
Alert(
title: Text("å
¥åãšã©ãŒ"),
message: Text(alertMessage),
dismissButton: .default(Text("OK"))
)
}
åŠã³ã»ææ³
åããŠã®SwiftéçºãéããŠãæ¹ããŠ0ããæ°ãããã®ãäœã楜ãããšãã£ã¬ã³ãžã®éææãå³ããããšãã§ããŸããããããããªåŠã³ããããŸãããäž»ã«ã¯ä»¥äžã®3ã€ã§ãã
1. 宣èšçUIã®æ°é®®ã
SwiftUIã䜿ã£ã宣èšçãªUIæ§ç¯ã¯ãPythonã§ã®GUIéçºãšã¯ç°ãªãæ°é®®ãªäœéšã§ããã
UIã®ç¶æ
ãã³ãŒãã§çŽæ¥è¡šçŸã§ãããããç·šéãçŽæçã«ããè¡ããŠããã¬ãã¥ãŒæ©èœã䜿ã£ãŠå³çµæã確èªã§ããã®ãéåžžã«äŸ¿å©ã§ãããç¥ããªããšã§ããªãèŠçŽ ãå€ãæããã®ããããŸãããããã¯GPTãªã©ã䜿ãã°ãåŒãåºããå¢ãããŠããããšæããŸãã
struct MainView: View {ã // SwiftUIã®ãã¥ãŒãå®çŸ©ããããã®æ§é äœãViewãããã³ã«ã«æºæ ããbodyããããã£ãæã€å¿
èŠãããã
var body: some View { // ãã¥ãŒã®UIãå®çŸ©
NavigationView { // éå±€çãªããã²ãŒã·ã§ã³ãæäŸ
TabView { // ã¿ãã䜿ã£ãããã²ãŒã·ã§ã³ãæäŸ
ContentView(trips: $trips, selectedTrip: $selectedTrip)ã// MainViewå
ã§è¡šç€ºãããã«ã¹ã¿ã ãã¥ãŒ
.tabItem { // ã¿ãããŒã«è¡šç€ºãããã¢ã€ãã ãå®çŸ©
Label(selectedTrip.isEmpty ? "æ
è¡" : selectedTrip, systemImage: "airplane")
}
}
}
}
}
SwiftUIã䜿çšããŠUIã宣èšåã§æ§ç¯ããããšã§ããã®éšåãã¢ããªã®äžéšãšããŠã©ãæ©èœããããçŽæçã«çè§£ã§ããŸãã
2. éçåä»ãã®å®å¿æ
Swiftã®éçåä»ããšããç¹åŸŽã¯ãã³ãŒããæžãéã«ããªãå®å¿ã§ããã
æãã°éçåä»ããã¡ãããšå®æã§ããã®ã¯ä»åãåããŠã§ããã
ã³ãŒãã£ã³ã°ãããéãScheduleæ§é äœã®ããããã£ã«åãæç€ºããããšã§åã«é¢ãããšã©ãŒãã³ã³ãã€ã«æã«çºèŠã§ããŸããããäžèŠãªå¡ãã¹ãæªç¶ã«é²ãããšãã§ããŸãããPythonã®åçåä»ãã®æè»ãããã£ãšããã¯ããã§é
åãªãã§ãããSwiftã®éçåä»ãããç¹ã«å€§èŠæš¡ãªãããžã§ã¯ãã§ã®ä¿¡é Œæ§ãé«ãããšèšãããã®ã¯ãã®éãã ãªãšå®æããŸããã
#pythonã®åçåä»ã
x = 10 # xã¯æŽæ°å
x = "Hello" # xã¯æåååã«å€æŽ
#swiftã®éçåä»ã
var x: Int = 10 // xã¯æŽæ°å
// x = "Hello" // ãšã©ãŒ: æååãæŽæ°åã®å€æ°ã«ä»£å
¥ã§ããªã
3.ããŒã¿ãã€ã³ãã£ã³ã°ãšã¯
ããŒã¿ãã€ã³ãã£ã³ã°ã¯ãSwiftUIã®å€§ããªç¹åŸŽã®äžã€ã§ãUIãšããŒã¿ã®åæãç°¡åã«è¡ãããšãã§ããŸããããã«ãããåžžã«ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãžææ°ã®ããŒã¿ãåæ ããããšãã§ãããããã³ãŒãã®å¯èªæ§ãåäžããŸãã
å®éã«ã³ãŒããæžããŠã¿ãŠããã¯ãSwiftãAppleã®ãã©ãããã©ãŒã ã«æé©åãããŠãããšããçç±ã倧ãããªãšæããŸãããPythonã ãšããŒã¿ã®å€æŽã«å¿ããŠãæç€ºçã«ã³ãŒããæžãå¿
èŠãå€ãæ°ãããŸãã
struct MainView: View {
// 芪ãã¥ãŒããåãåãããŒã¿ãtripsã¯æ
è¡ã®æ
å ±ãselectedTripã¯éžæãããæ
è¡åã
@Binding var trips: [String: [String: [Schedule]]]
@Binding var selectedTrip: String
var body: some View {
// ç»é¢éã®ç§»åãå¯èœã«ãããã¥ãŒã
NavigationView {
// ã¿ãããŒã衚瀺ãããã¥ãŒã
TabView {
// ContentViewã衚瀺ããtripsãšselectedTripãæž¡ãã
ContentView(trips: $trips, selectedTrip: $selectedTrip)
// ã¿ãã®ã©ãã«ãèšå®ãæ
è¡åã空ãªããæ
è¡ããšè¡šç€ºã
.tabItem {
Label(selectedTrip.isEmpty ? "æ
è¡" : selectedTrip, systemImage: "airplane")
}
}
}
}
}
@'State
-
å®çŸ©
- @'Stateã¯ããã¥ãŒã®å
éšã§ç¶æ
ã管çããããã®ããããã£ã©ãããŒã§ãã
ãã¥ãŒã®ç¶æ ãå€ãããšãSwiftUIã¯èªåçã«ãã¥ãŒãåæç»ããŸãã
- @'Stateã¯ããã¥ãŒã®å
éšã§ç¶æ
ã管çããããã®ããããã£ã©ãããŒã§ãã
-
ç¹åŸŽ
- å éšç¶æ : @'Stateã¯ããã¥ãŒã®å éšã§ã®ã¿äœ¿çšãããç¶æ ã管çããŸããä»ã®ãã¥ãŒããçŽæ¥ã¢ã¯ã»ã¹ããããšã¯ã§ããŸããã
- åæç»: @'Stateã®å€ã倿Žããããšããã¥ãŒãåæç»ãããUIãæŽæ°ãããŸãã
-
äŸ:
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
ãã®äŸã§ã¯ãcountã¯@'Stateã§ç®¡çãããŠããããã¿ã³ãæŒããšcountãå¢å ããããã¹ããæŽæ°ãããŸãã
ãããã«
ä»åã®éçºãéããŠåŸãçµéšã»ç¥èãåºã«ãåŒãç¶ãããã«è€éãªã¢ããªãæ°ããèšèªã«ææŠããŠã¿ãããšæããŸããç¹ã«ãããŒã¿ã®æ°žç¶åããããã¯ãŒã¯éä¿¡ãªã©ã次ã®ã¹ãããã«é²ãããã®æè¡ãåŠã³ããã§ããããŒã éçºãããŠã¿ãããªããã