質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

408閲覧

配列の保存方法と追加方法が分かりません。

uAd30HzDXwVQVwb

総合スコア4

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2022/06/04 16:14

編集2022/06/04 16:36

下記のコードについての質問が二つあります。
上二つのstructが分からない部分なのですが、3つ目のstructが無いと実行できないので載せています。
今回行いたいのは、カレンダーの下にある+ボタンを押して「タイトル」のTextFieldに文字を入力する。
そして、Enterキーを押した後に保存ボタンを押す。
すると、カレンダーの下にその「タイトル」が表示される。
これを、日毎に行えるようにしたいです。(日毎に自ら入力した別々のタイトルが表示されるという意味です。)

①struct CalendarPage で宣言している @State var array : [Date] = [] と @State var arraytitle : [String] = [] を再起動しても保存されたままにしたいです。@AppStorageと書くとエラーが出たので、userDefaultsでも書いたのですがViewの中だから不可能だとエラーが出ました。
どのような仕様にすれば良いでしょうか?

②初回のタイトル保存は出来るのですが、別の日を選択して行おうとするとTextFieldに入力はできるものの、カレンダーの下に表示されません。
struct SecondView にある @State var new = "" を毎回初期化が必要なのかとも考えましたが、その方法も分かりません。
どうすれば、その日毎に入力したタイトルを表示出来るのでしょうか?

質問が2つもありお手数をおかけしますが、よろしくお願いします。

swift

1import FSCalendar 2import CalculateCalendarLogic 3 4struct CalendarPage:View{ 5 @State private var show: Bool = false 6 @State var selectedDate = Date() 7 @State var array : [Date] = [] 8 @State var arraytitle : [String] = [] 9 var body: some View{ 10 VStack{ 11 Calendarpage(selectedDate:$selectedDate).frame(height:360) 12 HStack{ 13 Text(selectedDate,style:.date).padding() 14 Spacer() 15 Button(action:{self.show = true}){ 16 Text("+").font(.largeTitle).frame(width:50) 17 }.sheet(isPresented:self.$show){ 18 SecondView(show:$show,selectedDate:$selectedDate,array:$array,arraytitle:$arraytitle) 19 } 20 } 21 if(array.count == 0){ 22 } 23 else{ 24 ForEach(0..<array.count){index in 25 if(array[index] == selectedDate){ 26 Text("\(arraytitle[index])") 27 } 28 } 29 } 30 Spacer() 31 } 32 } 33} 34struct SecondView: View { 35 @Binding var show:Bool 36 @Binding var selectedDate:Date 37 @Binding var array:[Date] 38 @Binding var arraytitle:[String] 39 @State var new = "" 40 var body: some View { 41 VStack { 42 HStack{ 43 Spacer() 44 Button(action:{array.append(selectedDate);self.show.toggle()}){Text("保存")}.frame(width:75,height:75) 45 } 46 HStack{ 47 Text("タイトル") 48 TextField("",text:$new,onCommit:{arraytitle.append(new)}).overlay(RoundedRectangle(cornerRadius:1).stroke(Color.black, lineWidth:1)) 49 } 50 Spacer() 51 } 52 } 53} 54 55struct Calendarpage: UIViewRepresentable { 56 @Binding var selectedDate:Date 57 58 59 func makeUIView(context: Context) -> UIView { 60 typealias UIViewType = FSCalendar 61 let fsCalendar = FSCalendar() 62 fsCalendar.delegate = context.coordinator 63 fsCalendar.dataSource = context.coordinator 64 fsCalendar.appearance.headerTitleFont = UIFont.systemFont(ofSize: 20) 65 fsCalendar.appearance.weekdayFont = UIFont.systemFont(ofSize: 20) 66 fsCalendar.appearance.titleFont = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.bold) 67 fsCalendar.appearance.headerDateFormat = "yyyy/MM" 68 fsCalendar.appearance.todayColor = .gray 69 fsCalendar.appearance.selectionColor = .clear 70 fsCalendar.appearance.borderSelectionColor = .blue 71 fsCalendar.appearance.titleSelectionColor = .black 72 fsCalendar.appearance.borderRadius = 0 73 74 75 return fsCalendar 76 } 77 78 79 func updateUIView(_ uiView: UIView, context: Context) { 80 } 81 82 83 func makeCoordinator() -> Coordinator { 84 return Coordinator(self) 85 } 86 87 88 class Coordinator: NSObject, FSCalendarDelegateAppearance, FSCalendarDataSource{ 89 var parent : Calendarpage 90 91 92 init(_ parent: Calendarpage) { 93 self.parent = parent 94 } 95 96 97 func calendar(_ calendar:FSCalendar, didSelect date:Date, at monthPosition:FSCalendarMonthPosition){ 98 parent.selectedDate = date 99 } 100 101 102 func judgeHoliday(_ date : Date) -> Bool { // 祝日判定を行い結果を返すメソッド(True:祝日) 103 let tmpCalendar = Calendar(identifier: .gregorian) //祝日判定用のカレンダークラスのインスタンス 104 let year = tmpCalendar.component(.year, from: date) //祝日判定を行う年を取得 105 let month = tmpCalendar.component(.month, from: date) //祝日判定を行う月を取得 106 let day = tmpCalendar.component(.day, from: date) //祝日判定を行う日を取得 107 let holiday = CalculateCalendarLogic() //祝日判定のインスタンスの生成 108 return holiday.judgeJapaneseHoliday(year: year, month: month, day: day) 109 } 110 111 func getDay(_ date:Date) -> (Int,Int,Int){ //年月日をIntで取得 112 let tmpCalendar = Calendar(identifier: .gregorian) 113 let year = tmpCalendar.component(.year, from: date) 114 let month = tmpCalendar.component(.month, from: date) 115 let day = tmpCalendar.component(.day, from: date) 116 return (year,month,day) 117 } 118 119 120 func getWeekIdx(_ date: Date) -> Int{ //曜日判定(日曜日:1 〜 土曜日:7) 121 let tmpCalendar = Calendar(identifier: .gregorian) 122 return tmpCalendar.component(.weekday, from: date) 123 } 124 125 126 func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? { //土日や祝日の日の文字色を変える 127 if self.judgeHoliday(date){ //祝日判定をする(祝日は赤色で表示する) 128 return UIColor.red 129 } 130 let weekday = self.getWeekIdx(date) //土日の判定を行う(土曜日は青色、日曜日は赤色で表示する) 131 if weekday == 1 { //日曜日 132 return UIColor.red 133 } 134 else if weekday == 7 { //土曜日 135 return UIColor.blue 136 } 137 return nil 138 } 139 } 140}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

3つ目の構造体であるCalendarpageは省略しますが、
次のような感じになるでしょうか。
*あまり細かいところまで見られていないかもしれませんが、UserDefaultsに保存するところをポイントにコメントを入れています

swift

1import SwiftUI 2import FSCalendar 3import CalculateCalendarLogic 4 5struct CalendarPage:View{ 6 @State private var show: Bool = false 7 @State var selectedDate = Date() 8 @State var array : [Date] 9 @State var arraytitle : [String] 10 var body: some View{ 11 VStack{ 12 Calendarpage(selectedDate:$selectedDate).frame(height:360) 13 HStack{ 14 Text(selectedDate,style:.date).padding() 15 Spacer() 16 Button(action:{self.show = true}){ 17 Text("+").font(.largeTitle).frame(width:50) 18 }.sheet(isPresented:self.$show){ 19 SecondView(show:$show,selectedDate:$selectedDate,array:$array,arraytitle:$arraytitle) 20 } 21 } 22 if(array.count == 0){ 23 } 24 else{ 25 ForEach(0..<array.count, id:\.self){index in 26 if(equals(array[index], selectedDate)){ 27 Text("\(arraytitle[index])") 28 } 29 } 30 } 31 Spacer() 32 } 33 } 34 // イニシャライザでUserDefaultsから読み込みます 35 init() { 36 // @Stateをイニシャライザで指定する場合はちょっと特殊な記述になるみたいです 37 // https://developer.apple.com/documentation/swiftui/state/init(initialvalue:) 38 // https://capibara1969.com/1608/#toc5 39 let d = UserDefaults.standard.array(forKey: "arraykey") as? [Date] ?? [] 40 let s = UserDefaults.standard.array(forKey: "arraytitlekey") as? [String] ?? [] 41 _array = State(initialValue: d) 42 _arraytitle = State(initialValue: s) 43 } 44 // selectedDate(初期値)に時刻も含まれるためDateを==で比較すると同じと判断してくれませんでした 45 // 日付のみ保持するように変更するか、次のような感じで日付のみで比較するかでしょうか 46 func equals(_ date1: Date, _ date2: Date) -> Bool { 47 let calendar = Calendar.current 48 let components1 = calendar.dateComponents([.year, .month, .day], from: date1) 49 let components2 = calendar.dateComponents([.year, .month, .day], from: date2) 50 let result = components1 == components2 51 return result 52 } 53} 54struct SecondView: View { 55 @Binding var show:Bool 56 @Binding var selectedDate:Date 57 @Binding var array:[Date] 58 @Binding var arraytitle:[String] 59 @State var new = "" 60 var body: some View { 61 VStack { 62 HStack{ 63 Spacer() 64 Button(action:save){Text("保存")}.frame(width:75,height:75) 65 } 66 HStack{ 67 Text("タイトル") 68 TextField("",text:$new).overlay(RoundedRectangle(cornerRadius:1).stroke(Color.black, lineWidth:1)) 69 } 70 Spacer() 71 } 72 } 73 // 保存ボタンをタップしたタイミングでUserDefaultsに保存します 74 func save() { 75 array.append(selectedDate); 76 arraytitle.append(new); 77 UserDefaults.standard.set(array, forKey: "arraykey") 78 UserDefaults.standard.set(arraytitle, forKey: "arraytitlekey") 79 self.show.toggle() 80 } 81}

Use ForEach to provide views based on a RandomAccessCollection of some data type. Either the collection’s elements must conform to Identifiable or you need to provide an id parameter to the ForEach initializer.
The following example creates a NamedFont type that conforms to Identifiable, and an array of this type called namedFonts. A ForEach instance iterates over the array, producing new Text instances that display examples of each SwiftUI Font style provided in the array.
ForEach を使用して、あるデータ型の RandomAccessCollection に基づくビューを提供します。コレクションの要素は Identifiable に準拠する必要があるか、または ForEach イニシャライザに id パラメータを提供する必要があります。
次の例では、Identifiable に準拠する NamedFont タイプと、namedFonts というこのタイプの配列が作成されています。ForEach インスタンスは配列に対して反復し、配列で提供される各 SwiftUI Font スタイルの例を表示する新しい Text インスタンスを生成します。
https://developer.apple.com/documentation/swiftui/foreach

ForEachのところに警告が出ていると思います。
idパラメータを記述すると良いと思います。

①の方にも記述しましたが、時刻も含めて比較してしまっていることも原因かもしれません。

投稿2022/06/05 02:09

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uAd30HzDXwVQVwb

2022/06/05 04:40

迅速で丁寧な回答ありがとうございます! 質問したところだけでなく、警告部分も解決していただき、理想とした形になりました。 イニシャライザへの理解が全く足りていないので、URLまで付けていただき大変参考になりました。 ご回答を参考にさらにこのコードを発展させていけそうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問