[Swift] 10 自製ヘルスケアapp / DatePickerからの日付取得

DatePickerから日付を取得しつつ画面遷移するところでうまくいかなくなったので、段階を踏んで進めていくことにしました。

まずは日付の取得です。画面に取得日を仮表示させました。

次は画面遷移になります。

このコードはGitでtest branchに分岐させており、完成したらmainと合体させる予定です。Gitの練習も兼ねています。

C++ – Java – Pythonという進化の系譜とは異なる言語なので違和感が強いままですが、先を急がずだらだら進めていきます。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var selectedDate_from = Date()
    @State private var selectedDate_to = Date()
    @State private var selection = 1
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                Text("Health Manager Test")
                    .foregroundColor(Color(red:70/255,green:14/255,blue:68/255))
                    .font(.system(size: 32))
                    .padding()
                
                DatePicker("From", selection: $selectedDate_from, displayedComponents: .date)
                    .frame(width: 180, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))

                
                DatePicker("To", selection: $selectedDate_to, displayedComponents: .date)
                    .frame(width: 180, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                    .padding()
                
                Menu {
                    Picker(selection: $selection, label: Text("")) {
                        Text("グラフ").tag(1)
                        Text("リスト").tag(2)
                    }
                } label: {
                    Text("データタイプ")
                        .font(.system(size: 20))
                }
                .padding()
                
                Text("Date Picker From \(selectedDate_from)")
                    .font(.system(size: 20))
                
                Text("Date Picker To \(selectedDate_to)")
                    .font(.system(size: 20))
                
                Text("データタイプ \(selection)")
                    .font(.system(size: 20))
 
                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                    .padding()

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                
                Spacer()
                
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
       ContentView()
    }
}

[Swift] 09 自製ヘルスケアapp / プルダウンによる条件分岐

プルダウンメニューでデータタイプをグラフ、リストから選択し、ボタンを押すと測定項目のデータが表示されるようにしました。普通のif文です。

次は心拍変動のデータ取得、指定期間の反映、グラフ表示などです。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var selectiedDate_from = Date()
    @State private var selectiedDate_to = Date()
    @State private var selection = 1
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                Text("Health Manager")
                    .foregroundColor(Color(red:70/255,green:14/255,blue:68/255))
                    .font(.system(size: 40))
                    .padding()
                
                DatePicker("From", selection: $selectiedDate_from, displayedComponents: .date)
                    .frame(width: 180, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))

                
                DatePicker("To", selection: $selectiedDate_to, displayedComponents: .date)
                    .frame(width: 180, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                    .padding()
                
                Menu {
                    Picker(selection: $selection, label: Text("")) {
                        Text("グラフ").tag(1)
                        Text("リスト").tag(2)
                    }
                } label: {
                    Text("データタイプ")
                        .font(.system(size: 20))
                }
                .padding()
                
                if selection == 1 {
                    NavigationLink(destination: ContentView_HR_Graph(), isActive: $shouldShowSecondView_HR) {}
                    NavigationLink(destination: ContentView_HRV_Graph(), isActive: $shouldShowSecondView_HRV) {}
                } else {
                    NavigationLink(destination: ContentView_HR_List(), isActive: $shouldShowSecondView_HR) {}
                    NavigationLink(destination: ContentView_HRV_List(), isActive: $shouldShowSecondView_HRV) {}
                }
                

                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                    .padding()

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                
                Spacer()
                
            }
        }
    }
}

[Swift] 08 自製ヘルスケアapp / VSCodeの併用

VSCodeにSwift拡張機能を入れてコーディング、XCodeではBuild & RunとGit管理他に役割分担すると負担がかなり軽減しました。IDE嫌いの私でも快適にiOSアプリ開発できそうです。XCodeは想像をはるかに超えて難物でした。

Appleネイティブ言語に関するネット記事を漁っていくうちにObjective-CやUIkitに興味が出てきましたが、ここは我慢してSwiftで基礎力を身につけることに専念します。

XCodeやSwiftに対する不満をぶちまけたら改善策が色々浮かんできました。プログラマにとって不平不満は推進力になります。

[Swift] 07 自製ヘルスケアapp / Simulatorと実機の乖離

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1, iPhone11]

前回の続きです。

iPhone11実機ではDatePickerの日付Styleがshort(1/1/22)ではなくmedium(Jan 1, 2022)で表示されてしまいます。Simulatorではshortになります。

SwiftUIではどうやってもshortにできませんでした。UIkitならできるのでしょうか?

一事が万事。SwiftUIは細かいところでいろいろ不備がありそうで創作意欲が萎えています。早めにUIkitにシフトする方が快適に開発できそうな気がしてきました。

あるいはSwiftUIはそういうものと割り切り、仕様に合わせて適当にコーディングするか迷います。今のところ愛着はゼロですからドライに使いこなしましょうか。

[Swift] 06 自製ヘルスケアapp / Picker

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1]

データタイプを選択させるためプルダウンメニューを配置しました。

フォントサイズの設定に手間取りました。Swiftの文法で引っかかったのは初めてです。Pickerの最初のラベルが反映されないので空文字にしましたが、なぜそうなるのか謎です。

あとiPhone13では正常に表示されますが、iPhone11ではFromとToがまともに表示されません。月が英語表記になっています。英語表記になって幅が広がったためラベルがはみ出したのでしょう。何らかの対策が必要になります。表記を統一できない場合は、自分用のアプリなのでiPhone13を切り捨てることになります。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var selectiedDate_from = Date()
    @State private var selectiedDate_to = Date()
    @State private var selection = 1
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                Text("Health Manager")
                    .foregroundColor(Color(red:70/255,green:14/255,blue:68/255))
                    .font(.system(size: 40))
                    .padding()
                
                DatePicker("From", selection: $selectiedDate_from, displayedComponents: .date)
                    .frame(width: 130, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                
                DatePicker("To", selection: $selectiedDate_to, displayedComponents: .date)
                    .frame(width: 130, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                    .padding()
                
                Menu {
                    Picker(selection: $selection, label: Text("")) {
                        Text("グラフ").tag(1)
                        Text("リスト").tag(2)
                    }
                } label: {
                    Text("データ選択")
                        .font(.system(size: 20))
                }
                .padding()
                
                NavigationLink(destination: ContentView_HR(), isActive: $shouldShowSecondView_HR) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                    .padding()
                
                NavigationLink(destination: ContentView_HRV(), isActive: $shouldShowSecondView_HRV) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                
                Spacer()
                
            }
        }
    }
}

[Swift] 05 自製ヘルスケアapp / DatePicker

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1]

日付範囲を指定できるようにして、ガワを整えました。さすがAppleのネイティブ言語だけあって直感的にすらすら書けますね。日本語記事が多いので助かります。

後は他のContentViewとContentViewModelを書いていきます。

データはリストではなくグラフで表示したいです。さらにiCloudにデータを保存できたらSwiftデビュー作は一応完成といったところでしょうか。

XCodeのBuild&Runが結構遅いのでもっとマシンパワーが欲しいです。M1 Proか今秋発売が予想されるM2あたりですかね。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var selectiedDate_from = Date()
    @State private var selectiedDate_to = Date()
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                Text("Health Manager")
                    .foregroundColor(Color(red:70/255,green:14/255,blue:68/255))
                    .font(.system(size: 40))
                    .padding()
                
                DatePicker("From", selection: $selectiedDate_from, displayedComponents: .date)
                    .frame(width: 130, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                    .padding()
                
                DatePicker("To", selection: $selectiedDate_to, displayedComponents: .date)
                    .frame(width: 130, height: 50)
                    .scaleEffect(x: 1.5, y: 1.5)
                    .font(.system(size: 20))
                    .padding()
                
                NavigationLink(destination: ContentView_HR(), isActive: $shouldShowSecondView_HR) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                    .padding()
                
                NavigationLink(destination: ContentView_HRV(), isActive: $shouldShowSecondView_HRV) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                        .foregroundColor(Color.white)
                }
                    .frame(width: 200, height: 100)
                    .background(Color(red:61/255,green:110/255,blue:218/255))
                    .font(.system(size: 24))
                    .cornerRadius(24)
                
                Spacer() // 上詰め
                
            }
        }
    }
}

[Swift] 04 自製ヘルスケアapp ボタン設定 / 色・フォントサイズ他

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1]

ボタンを角丸にして色を付けました。こういうことができるようになるとコーディングが楽しくなってきます。

色をRGBで指定する際、0から1.0で指定するのが面倒です。分数は使えます。自製アプリ ColorSampleJPにRGB(0 – 1.0)を追加しなければ。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: ContentView_HR(), isActive: $shouldShowSecondView_HR) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                        .foregroundColor(Color.white)
                }
                .frame(width: 200, height: 100)
                .background(Color(red:61/255,green:110/255,blue:218/255))
                .font(.system(size: 24))
                .cornerRadius(24)
                .padding()
                
                NavigationLink(destination: ContentView_HRV(), isActive: $shouldShowSecondView_HRV) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                    .foregroundColor(Color.white)
                }
                .frame(width: 200, height: 100)
                .background(Color(red:61/255,green:110/255,blue:218/255))
                .font(.system(size: 24))
                .cornerRadius(24)
                
            }
        }
    }
}

[Swift] 03 自製ヘルスケアapp / ボタン配置, 画面遷移

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1]

ボタンを配置して見たいデータを選択できるようにしました。ボタンの大きさやレイアウトはこれから調整します。

Gitも並行して学んでいるのでコーディング進度は今一つですが、そのうち慣れるでしょう。ただコードを複製し加工していく作業をするにはGitの痕跡を残す機能は邪魔でしょうがないです。

Gitがあまりにうっとおしいため、VSCodeに戻りPythonのKivyでiOS開発しようかとも思いましたが、HealthKitはSwiftなどAppleネイティブ言語でしか扱えないはずなので思い直しました。編集してすぐにコミットすれば問題ありません。

import SwiftUI
import CoreData

struct ContentView: View {
    @State private var shouldShowSecondView_HR: Bool = false
    @State private var shouldShowSecondView_HRV: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: ContentView_HR(), isActive: $shouldShowSecondView_HR) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HR = true
                } label: {
                    Text("心拍数")
                }
                 
                NavigationLink(destination: ContentView_HRV(), isActive: $shouldShowSecondView_HRV) {
                    EmptyView()
                }

                Button {
                    shouldShowSecondView_HRV = true
                } label: {
                    Text("心拍変動")
                }
            }
        }
    }
}

[Swift] 02 自製ヘルスケアapp / アイコン設定

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.3.1]

まずはアプリアイコンをAdobe XDで作り、プロジェクトに登録してみました。

App icon Generatorというサイトで1024*1024ファイルから即席アイコンセット(iPhone 11個, iPad 13個)を作成しましたが、macOS用よりサイズを大きめにする必要があったようで図形が小さくなってしまいました。AppleのサイトからiOS用テンプレを入手して作り直します。

近々自製アプリImageInspector(C++)の機能を拡張し、ワンクリックでiOSアプリ用アイコンセットを作れるようにします。

[Swift] 01 自製ヘルスケアapp / 製作着手

[Mac mini M1, MacOS Monterey 12.3.1, XCode 13.2.1]

Swiftの学習に着手しました。まずは各種ヘルスケアデータの取得方法を学んでいきます。

最初は欲しいコーディング情報が見当たらず右往左往していましたが、わかりやすい日本語サイトが見つかってからは比較的スムーズにBuild&Runできました。

Swiftの印象はポインタのないC++といったところです。難易度はJava以上、C++以下と予想します。構造体データとかC言語の知識がないと苦戦しそうです。

Python, Java, C++と学んできた私にはちょうどいい感じです。

参考サイト