はじめに
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