【情報共有アプリ】ログイン画面を作る

App

私が開発したiPhoneアプリについて、経験を元に開発手法等の基礎的な知識から具体的な手順まで、分かりやすく解説していきます。

本記事ではアプリのログイン画面に作成方法について紹介します。アプリ開発はをしてみたい人の力になれましたら幸いです。

完成画面

ユーザー名を入力、利用規約に☑︎を入れたら登録に進むことができます。登録完了画面がある理由は入力ミスがあれば戻るためです。

機能一覧

・文字入力機能
・☑︎する機能
・ゲストでログイン機能
・ユーザー情報登録機能
・モーダル表示機能(利用規約)

プログラム

ログイン状態の判断

別ファイルでログイン状態を管理し、まだログイン状態ではない場合にログイン画面を表示しています。そこを判断しているのが以下のプログラムです。(ログイン画面の前に実行しているファイル)

import SwiftUI

struct RootView: View {
    @AppStorage("islogin") var testAppStorage = false
    
    var body: some View {
        if testAppStorage {
            ContentView()
        }else{
            LoginView()
        }
    }
}

@AppStorage:SwiftUIでユーザーのデフォルトの永続的なストレージに簡単にアクセスするためのプロパティラッパーであり、シンプルなキー/値ペアを保存および読み取りが可能。
このプロパティは “islogin”というキーでユーザーデフォルトに保存されている。
※初期値でfalseを入れているようになっていますが、初回の起動で保存された値が存在する場合、それが優先されます。つまりtestAppStorageは起動時にユーザーデフォルトに保存されている値になります。

RootViewはエントリーポイントで起動されています。※以下の記事で紹介しています。

ログイン画面

以下がログイン画面全体の説明になります。

import SwiftUI
import CoreData
import FirebaseDatabase

struct LoginView: View {
    //ユーザー名を格納するための変数
    @State var name = ""
    //メールを格納するための変数
    @State var mail = ""
    //登録完了画面を出すためのステータス
    @State var status = false
    //規約画面を出すためのステータス
    @State var kiyaku = false
    //規約に同意した状態を表すステータス
    @State var check = false
    //登録するユーザー名に被りがあった際に使用
    @State var yes_name = ""
    
    //ログイン状態をユーザーデフォルトに保存
    @AppStorage("islogin") var testAppStorage = false
    //ユーザー名をユーザーデフォルトに保存
    @AppStorage("myname") var nameAppStorage = ""

    //Firebase Realtime Databaseを使用してデータベースにアクセスする
    let ref = Database.database().reference()
    
    var body: some View {
        NavigationView{
            ScrollView {
                VStack{
                    Image("gazou").resizable()
                        .frame(width: 45, height: 45)
                    Text("NowShare").font(.largeTitle).bold().foregroundColor(.yellow)
                }.padding(.vertical, 70)
                
                VStack {
                    TextField("ニックネーム *", text: $name).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
                    if yes_name != "" {
                        Text(yes_name).font(.system(size: 13)).foregroundColor(.red)
                    }
                    TextField("メールアドレス:任意", text: $mail).textFieldStyle(RoundedBorderTextFieldStyle()).padding()
                    
                    //チェックボックスのステータスに応じてUIを変更する処理
                    HStack{
                        Button(action:{
                            self.check.toggle()
                        }){
                            if check{
                                Text("☑︎").padding(.leading)
                            }else{
                                Text("□").padding(.leading)
                            }
                        }
                        Text("利用規約に同意する")
                        Spacer()
                        
                    }.padding(.bottom,2)

                    //利用規約ボタンを押下しKiyaku()をモーダル表示
                    HStack {
                        Button(action: {
                            kiyaku = true
                        }){
                            Text("※利用規約を確認する").frame(alignment: .leading)
                        }.sheet(isPresented: $kiyaku, onDismiss: {
                            kiyaku = false
                        }){
                            Kiyaku()
                        }
                        Spacer()
                    }.padding(.leading)
                }
                
                //名前が入力、チェックボックスが☑︎であれば登録に進める。
                VStack {
                    if name != "" && check == true {
                        Button(action: {
                            yes_name = ""
                            //Firebase Realtime Databaseからデータを取得し、変数valueへ配列の形で登録してある名前を格納。
                            ref.child("Person").observeSingleEvent(of: .value, with: { snapshot in
                                if let value = snapshot.value as? [String:String] {
                                    for i in value {
                                        //登録予定の名前が既に存在していれば登録できない。
                                        if name == i.value{
                                            yes_name = "そのユーザー名は既に使用されています"
                                        }
                                    }
                                    if yes_name == "" {
                                        self.status.toggle()
                                    }
                                }
                            })
                        }){
                            //登録ボタンを押下しSigninView()をモーダル表示
                            Text("登録").font(.title2).bold().padding()
                        }.sheet(isPresented: $status, onDismiss: {
                            status = false
                        }){
                            SigninView(name: $name, pwd: $pwd, phone: $phone, mail: $mail)
                        }
                      //最初はボタンを押せない状態にしておく
                    } else {
                        Text("登録").font(.title2).foregroundColor(Color.gray).padding()
                    }
                    //ユーザー登録せずにアプリを使えるようにしている。(Apple Storeからの要望)
                    Button(action: {
                        nameAppStorage = "ゲスト"
                        testAppStorage = true
                    }){
                        Text("ゲストでログインする").foregroundColor(Color.black).underline().padding()
                    }
                }.padding(50)
            }
        }.navigationViewStyle(.stack)
    }
}

以下が登録ボタンを押した後の登録完了画面になります。

struct SigninView: View {
    @AppStorage("islogin") var testAppStorage = false
    @AppStorage("myname") var nameAppStorage = ""
   
    //前画面の情報を格納する変数を指定
    @Binding var name: String
    @Binding var mail: String

    //Core Data の NSManagedObjectContext へのアクセスを提供するためのプロパティラッパー。Core Data のコンテキストにアクセスを提供
    @Environment(\.managedObjectContext) private var viewContext

    //モーダルビューを閉じるために使用
    @Environment(\.presentationMode) var presentationMode
    
    let ref = Database.database().reference()
    
    var body: some View {
        NavigationView {
            VStack{
                Text("登録を完了させますか?").font(.largeTitle).fontWeight(.bold).padding(3)
                Text("※まだ完了していません").font(.body).fontWeight(.bold).foregroundColor(.red)
                HStack{
                    Button(action: {
                        self.presentationMode.wrappedValue.dismiss()
                    }){
                        Text("<<戻る").bold().font(.headline).foregroundColor(Color.gray).padding()
                    }
                    //Firebase Realtime Databaseへデータを格納する処理。ユーザー名とログイン状態をユーザーデフォルトに保存
                    Button(action: {
                        ref.child("Person/" + name).setValue(name)
                        nameAppStorage = name
                        testAppStorage = true
                        addItem()
                    }){
                        Text("確定>>").bold().font(.headline).padding()
                    }
                }
            }
        }
    }
    //Core Dataへデータを保存させるための処理。
    func addItem() {
        withAnimation {
            let newItem = Person(context: viewContext)
            newItem.name = name
            newItem.passwords = pwd
            newItem.phone = phone
            newItem.mail = mail
            //データベース保存+エラーハンドリング
            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

以下が利用棄規約を押した後の画面になります。

struct Kiyaku: View {
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    Text("ここに利用規約の内容を記載").padding()
                    Divider().frame(height: 1)
                        .background(Color.black)
                    Button(action: {
                        self.presentationMode.wrappedValue.dismiss()
                    }){
                        Text("閉じる").padding()
                    }
                }
            }
        }
    }
}

プロパティラッパーの説明は以下の記事で行なっております。

以上がログイン画面の説明になります。次はホーム画面についての記事を出します。アプリ開発は初めての方にとっては難しいと思います。こ私のこの記事や他の開発に関する記事が見てくださる皆様の力になれますと幸いです。

アプリ”NowShare”をダウンロード
情報共有アプリ"NowShare"
今からみんなでナレッジ共有! 本当に欲しい情報をキャッチ&リリース 教えてあげたい情報を知りたい人にすぐに共有。 ためになった情報にはいいねを押して盛り上げよう!
Appエンジニア
ナスジニアをフォローする
🍆ナスジニアのブログ(iPhoneアプリ開発)

コメント

タイトルとURLをコピーしました