Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【SwiftUI】IDとパスワードでログインする画面を実装する

 

はじめに

IDとパスワードでログインする画面をSwiftUIで実装してみました。

 

※ログイン機能については以下の記事でも取り上げています。

【SwiftUI】LINEログインの実装 - Swift・iOS

【SwiftUI】Sign In with Appleの実装 - Swift・iOS

【SwiftUI】ログイン画面の実装まとめ - Swift・iOS

 

開発環境

Xcode 12.0.1

・Swift 5.3

 

実装

実装方針

MVVMに沿った実装にしたいため、以下のようにView、ViewModel、Modelへ処理を分けたいと思います。

※参考:PEAKS(ピークス)|iOSアプリ設計パターン入門

View

ユーザー操作の受付と画面表示を担当

・IDとパスワードを入力するTextFieldを表示

・IDとパスワードに入力された文字をViewModelに通知

・ログインボタンを表示

・ログインボタンが選択されたらViewModelに通知

 

ViewModel

Viewに表示するためのデータを保持したり、Viewからイベントを受け取ってModelの処理を呼び出したりデータを更新する

・IDとパスワードそれぞれに入力された文字を保持する変数

・IDとパスワードが半角英数で入力されている状態か保持する変数

・ログインボタンの選択状態を保持する変数

・ログインボタンが選択されたらModelからログイン処理を呼び出す

 

Model

UIに関係しないロジックを持つ

・ログイン処理(本記事では省略)

 

その他

・半角英数かどうか判別するStringの拡張

 

コード

LoginView.swift

import SwiftUI

struct LoginView: View {
    @ObservedObject var viewModel: LoginViewModel
    
    init(viewModel: LoginViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack(spacing: 15) {
            Text("アカウントIDでログイン")
                .bold()
            
            // 入力した文字をLoginViewModelの変数idに通知
            TextField("ID(半角英数)", text: $viewModel.id)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .frame(width: 300)
            
            // 入力した文字をLoginViewModelの変数passwordに通知
            TextField("パスワード(半角英数)", text: $viewModel.password)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .frame(width: 300)
            
            Button(action: {
                // ボタンが選択されたことをLoginViewModelの変数isLoginButtonTappedに通知
                viewModel.isLoginButtonTapped = true
            }) {
                Text("ログイン")
            }
            .frame(width: 200, height: 45)
            .foregroundColor(Color.white)
            // ボタンの有効/無効状態に合わせて背景の色を変更
            .background(viewModel.isValidId && viewModel.isValidPassword ? Color.blue : Color.gray)
            .cornerRadius(10, antialiased: true)
            // IDとパスワードがどちらも半角英数で入力されていればボタンを有効にする
            .disabled(!viewModel.isValidId || !viewModel.isValidPassword)
        }
    }
}

struct LoginView_Previews: PreviewProvider {
    static var previews: some View {
        LoginView(viewModel: LoginViewModel())
    }
}

 

LoginViewModel.swift

import Combine

class LoginViewModel: ObservableObject {
    @Published var id: String = ""
    @Published var password: String = ""
    
    // TextFieldに入力した文字が半角英数かどうか判別する変数
    @Published var isValidId: Bool = false
    @Published var isValidPassword: Bool = false
    
    @Published var isLoginButtonTapped: Bool = false
    
    private var disposables = [AnyCancellable]()
    
    init() {
        $id
            .sink(receiveValue: {
                self.isValidId = $0.isAlphanumeric && !$0.isEmpty ? true : false
            })
            .store(in: &disposables)
        
        $password
            .sink(receiveValue: {
                self.isValidPassword = $0.isAlphanumeric && !$0.isEmpty ? true : false
            })
            .store(in: &disposables)
        
        $isLoginButtonTapped
            .sink(receiveValue: { isTapped in
                if isTapped == true {
                    print("ここでログイン処理を呼び出す")
                }
            })
            .store(in: &disposables)
    }
}

 

String+Extensions.swift

extension String {
    // 半角英数かどうか判別
    var isAlphanumeric: Bool {
        return !isEmpty && range(of: "[^a-zA-Z0-9]", options: .regularExpression) == nil
    }
}

 

SceneDelegate.swift

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 起動後の画面をログイン画面に設定
        let viewModel = LoginViewModel()
        let loginView = LoginView(viewModel: viewModel)

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: loginView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

 

おわりに

次回はLINEログインの実装について記事にしたいと思います。 

 

参考

詳細! SwiftUI iPhoneアプリ開発入門ノート iOS 13 + Xcode11対応 | 大重 美幸 |本 | 通販 | Amazon

PEAKS(ピークス)|iOSアプリ設計パターン入門