見出し画像

ChatGPTに教えてもらえばAIアプリだって作れる様になるはず‼︎ 3.Tip Calculator #機械学習による人間学習

はじめに

このブログでは、ChatGPTで作成した「AIアプリを作れる様になるまでの100個のアプリ案」を実際に作り、学んだことや失敗したこと、感じたことを記していきます。

各記事のページ下部にはChatGPTによるStep by Stepガイドを貼付し、学習内容をトレース出来る様にしています。

プログラミング初心者の方や新しくスキルを身に付けようとしている方の参考になれば幸いです。

(※本ブログはマガジン「ChatGPTに教えてもらえばにまとめてあります。)


今回のアプリ

三つ目のアプリはTip Calculatorです。欧米の商習慣であるチップの金額を計算するアプリです。チップの比率を選択式にして支払い合計額を算出します。セレクターで選択出来る様にするという所がこれまでにない部分でしょうか。

コードはページ下部にあります

カスタマイズ

  • 割り勘機能

    • デフォルトの状態に割り勘機能を付与しました。

  • ScrollView追加

    • 金額を一番上のTextfieldに入力する際、下から数字入力用のキーボードが出てきますが、キーボードにより全パーツが上に移動してしまいました。ScrollViewを加えることでその挙動を防ぎました。

学習したこと

  • .keyboardType(.decimalPad)

    • テンキーが出ます。

  • Picker

    • テンキーなどで入力するのではなく、ボタンなどすでに表示されている中から選択する様に出来る。

    • pickerStyle( )

      • Pickerの末尾に付けることでPickerの種類を変更出来る。今回のアプリだとTip percentageを変更するセグメントスタイルのセレクタが採用されている。

  • ScrollView{ }

    • ScrollViewで囲んだ部分が上下にスクロール出来る様になる。テンキーが出てきてもレイアウトが崩れない。

感想

ちょっとずつ新しい要素が入ってきてるのが分かり、教育プログラムとしてちゃんと構成されていそうで面白いですね。プログラム構成もコード作製もChatGPTに頼り切りなので、どこかで継続不能にならないか今から少し不安です。

今回新しかったのはボタンでした。前回の時計は.onAppearを使うことでVstackが画面に表示されることがトリガーとなり、時計が更新されるfunctionが実行されましたが、今回はボタンを押すことで支払いの合計金額が算出される様になっていました。トリガーにfunctionを設定して機能性を持たせるというのがSwiftのパターンみたいです。

また、カスタマイズでは金額入力時、テンキーが出現するとレイアウトが全体的に上に行ってしまうことが嫌だったので修正しました。

ちなみにカバー画像もChatGPTで作成しました。意味不明なボタンもありますが、イメージとして機能しない訳ではないのでそのまま使いました。細かい部分に拘らなければ幅広い用途に使えそうです。

ChatGPTの回答


以下では、XcodeでSwiftUIを使用してチップ計算機(Tip Calculator)アプリを作成する手順をステップバイステップで説明します。このアプリでは、ユーザーが請求額を入力し、チップのパーセンテージを選択すると、合計金額(請求額 + チップ)が計算されます。

1. Xcodeを開いて新規プロジェクトを作成

  1. Xcodeの起動

    • アプリケーションフォルダからXcodeを開きます。

  2. 新規プロジェクトの作成

    • 「Create a new Xcode project」を選択するか、File > New > Project を選択します。

  3. テンプレートの選択

    • iOSの項目からAppを選択し、Nextをクリックします。

  4. プロジェクトの詳細を設定

    • Product Name: 例として「TipCalculator」と入力します。

    • Team: Apple Developerアカウントを持っている場合は選択し、なければ「None」を選択してローカルでテストできます。

    • Organization Identifier: 例として「com.yourname」のように入力します。

    • Interface: SwiftUI を選択します。

    • Language: Swift を選択します。

    • Nextをクリックし、任意のフォルダにプロジェクトを保存します。

  5. プロジェクト作成

    • Createをクリックします。

2. ContentView.swiftを編集してチップ計算機を作成

ContentView.swiftファイルを開きます。デフォルトのテンプレートコードの代わりに以下の手順を追加し、チップ計算機を作成します。

ステップ 1: State変数を定義

請求額、選択したチップのパーセンテージ、計算された合計額を保持するための変数を追加します。

import SwiftUI

struct ContentView: View {
    @State private var billAmount: String = "" // ユーザーが入力する請求額
    @State private var tipPercentage: Int = 15 // デフォルトのチップパーセンテージ
    @State private var totalAmount: Double = 0.0 // 合計(請求額 + チップ)

    var body: some View {
        VStack(spacing: 20) {
            Text("Tip Calculator")
                .font(.largeTitle)
                .padding()

ステップ 2: 請求額入力用のTextFieldを追加

ユーザーが請求額を入力できるようにTextFieldを配置します。

            TextField("Enter bill amount", text: $billAmount)
                .keyboardType(.decimalPad) // 数字と小数点のみ入力を許可
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

ステップ 3: チップのパーセンテージを選択するPickerを追加

ユーザーがチップパーセンテージを選択できるよう、Pickerを設置します。

            Picker("Tip Percentage", selection: $tipPercentage) {
                ForEach([10, 15, 20, 25, 30], id: \.self) { percentage in
                    Text("\(percentage)%").tag(percentage)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            .padding()

ステップ 4: 合計を計算するボタンを追加

タップすると合計金額を計算するボタンを用意します。

            Button(action: calculateTotal) {
                Text("Calculate Total")
                    .font(.headline)
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .padding()

ステップ 5: 合計金額を表示

ボタンの下に合計金額を表示します。

            Text("Total Amount: \(totalAmount, specifier: "%.2f")")
                .font(.title2)
                .padding()

ステップ 6: 計算関数を追加

入力された請求額と選択したチップのパーセンテージから合計金額を計算するcalculateTotal関数を定義します。

    func calculateTotal() {
        guard let bill = Double(billAmount) else {
            totalAmount = 0.0 // 無効な入力の場合は合計をリセット
            return
        }
        let tip = bill * Double(tipPercentage) / 100
        totalAmount = bill + tip
    }
}

3. 完成したコード例

以下は、ContentView.swiftの完全なコード例です。

import SwiftUI

struct ContentView: View {
    @State private var billAmount: String = ""
    @State private var tipPercentage: Int = 15
    @State private var totalAmount: Double = 0.0

    var body: some View {
        VStack(spacing: 20) {
            Text("Tip Calculator")
                .font(.largeTitle)
                .padding()

            TextField("Enter bill amount", text: $billAmount)
                .keyboardType(.decimalPad)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

            Picker("Tip Percentage", selection: $tipPercentage) {
                ForEach([10, 15, 20, 25, 30], id: \.self) { percentage in
                    Text("\(percentage)%").tag(percentage)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            .padding()

            Button(action: calculateTotal) {
                Text("Calculate Total")
                    .font(.headline)
                    .padding()
                    .frame(maxWidth: .infinity)
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .padding()

            Text("Total Amount: \(totalAmount, specifier: "%.2f")")
                .font(.title2)
                .padding()

            Spacer() // 画面上部に内容を寄せる
        }
        .padding()
    }

    func calculateTotal() {
        guard let bill = Double(billAmount) else {
            totalAmount = 0.0
            return
        }
        let tip = bill * Double(tipPercentage) / 100
        totalAmount = bill + tip
    }
}

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

4. アプリを実行する

  1. シミュレータの選択

    • Xcode上部のデバイス選択メニューから(例: iPhone 14など)シミュレータを選択します。

  2. アプリの実行

    • 再生ボタン(▶)をクリックするか、Cmd + Rを押してビルド&実行します。

  3. アプリのテスト

    • 請求額(例: 100)を入力します。

    • チップパーセンテージ(例: 20%)を選択します。

    • 「Calculate Total」ボタンをタップします。

    • 請求額 + チップの合計金額がボタンの下に表示されます。

5. カスタマイズや拡張(オプション)

アプリをさらに便利にするためのアイデアをいくつか紹介します。

a. 複数人で割り勘する機能

  • 複数人で合計金額を分割できるようにします。例として「Number of People」のTextFieldを追加し、計算時に人数で割るように変更することができます。

@State private var numberOfPeople: Int = 1
// 合計計算をnumberOfPeopleで割るようにロジックを更新

b. エラーハンドリングの強化

  • ユーザーが文字列など不正な入力をした場合にアラートを表示するなど、より丁寧なエラーハンドリングを行うこともできます。

c. ダークモード対応

  • ライトモードとダークモードの両方でテストを行い、必要に応じて色のコントラストを調整するとさらに見やすいアプリになります。

まとめ

これでSwiftUIを使ったシンプルなチップ計算機アプリが完成です!
おめでとうございます 🎉
ここからさらに機能やデザインを追加したり、コードを整理したりして、ご自身のアプリをより魅力的に仕上げてみてください。その他のガイダンスや拡張機能について知りたい場合は、お気軽にお知らせください!


カスタマイズ例


import SwiftUI

struct ContentView: View {
    // ステップ1: State変数の定義
    // 請求額、選択されたチップの割合、計算された合計金額を保持する変数を追加
    @State private var billAmount: String = "" // ユーザーが入力する請求額
    @State private var tipPercentage: Int = 15 // デフォルトのチップ割合
    @State private var totalAmount: Double = 0.0 // 合計請求額(請求額 + チップ)

    // 機能拡張1: 割り勘機能の追加
    @State private var numberOfPeople: Int = 1 // 人数
    @State private var splitAmount: Double = 0.0 // 一人あたりの支払額

    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                Text("Tip Calculator")
                    .font(.largeTitle)
                    .padding()

                // ステップ2: 請求額入力用のTextFieldを追加
                // ユーザーが請求額を入力できるTextField
                TextField("Bill Amount", text: $billAmount)
                    .keyboardType(.decimalPad) // 数字入力用キーボード(小数点対応)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .padding()

                // ステップ3: チップの割合を選択するPickerを追加
                // ユーザーがチップの割合を選択できるPicker
                Picker("Tip Percentage", selection: $tipPercentage) {
                    ForEach([10, 15, 20, 25, 30], id: \.self) { percentage in
                        Text("\(percentage)%").tag(percentage)
                    }
                    // "\" は文字列として変数をそのまま扱うためのエスケープシーケンス
                }
                .pickerStyle(SegmentedPickerStyle()) // セグメントスタイルのPicker(画像のような表示になる)
                .padding()

                // ステップ4: 合計金額を計算するボタンを追加
                // タップすると合計金額を計算するボタン
                Button(action: calculateTotal) {
                    Text("Calculate Total")
                        .font(.headline)
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background(Color.blue)
                        .foregroundColor(.white)
                        .cornerRadius(10)
                }
                .padding()

                // ステップ5: 合計金額の表示
                // 計算された合計金額をボタンの下に表示
                Text("Total Amount: \(totalAmount, specifier: "%.2f") 円")
                    .font(.title)
                    .padding()

                // 機能拡張1: 割り勘機能の追加
                HStack {
                    Text("Splited by:")
                    Picker("Number of People", selection: $numberOfPeople) {
                        ForEach(1..<20, id: \.self) { people in
                            Text("\(people)").tag(people)
                        }
                    }
                }
                .font(.title)

                Text("Split Amount: \(splitAmount, specifier: "%.2f") 円")
                    .font(.title)
                    .padding()
            }
            .padding()
        }
        .padding(.bottom, 20)
        .onTapGesture {
            hidekeyboard()
        }
    }

    // ステップ6: 計算処理の追加
    // 入力された請求額と選択されたチップ割合に基づき、合計金額を計算する関数
    func calculateTotal() {
        guard let bill = Double(billAmount) else {
            totalAmount = 0
            splitAmount = 0
            return
        }
        let tip = bill * Double(tipPercentage) / 100
        totalAmount = bill + tip
        splitAmount = totalAmount / Double(numberOfPeople)
    }
}

extension View {
    func hidekeyboard(){
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

#Preview {
    ContentView()
}

いいなと思ったら応援しよう!