- 投稿日:2020-11-21T23:15:32+09:00
[iOS/Swift]Alamofire を利用したアプリ実装(郵便番号検索アプリを例に)
書くこと
Alamofire を利用した API 呼び出しを利用してアプリを実装する
書いた理由
Alamofire を利用した API 呼び出し方法を忘れた時に確認する
参考にした記事
標準とAlamofireでAPIコール処理を書き比べてみる(Swift)
上記記事に紹介されていたコードに、UIを実装した
(すごくわかりやすい記事です)前提条件
- テキストフィールド、ボタンおよび検索結果を表示するラベルは
Main.storyboard
で設定- 上記要素は、
ViewController.swift
に紐づけているCocoaPods
を利用してAlamofire
はすでに導入済であるアプリの機能
テキストフィールドに郵便番号を入力し[Seach]ボタンをタップすると、ラベル(水色)にその郵便番号に対応する住所を表示する。
・郵便番号が入力されていない場合や入力した文字が7桁ではない場合はアラートを表示する
コード例
AddressModel.swift// このコードは参考にした記事より流用した struct AddressModel: Decodable { var results: [Result] struct Result: Decodable { var address1: String var address2: String var address3: String var kana1: String var kana2: String var kana3: String } }ViewController.swiftimport UIKit import Alamofire class ViewController: UIViewController { private var addresses: AddressModel? @IBOutlet weak var zipCodeTextField: UITextField! @IBOutlet weak var seachButton: UIButton! @IBOutlet weak var resultLabel: UILabel! @IBAction func tapSeachButton(_ sender: Any) { self.getAddress(zipCode: zipCodeTextField.text) } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } private func getAddress(zipCode: String?) { self.validate(zipCode: zipCode) let baseUrl = "https://zipcloud.ibsnet.co.jp/api/" let searchUrl = "\(baseUrl)search" let parameters: [String: Any] = ["zipcode": zipCode!] let headers: HTTPHeaders = ["Content-Type": "application/json"] self.requestAPI(url: searchUrl, parameters: parameters, headers: headers) } private enum ErrorType:String { case zipCodeNil = "郵便番号が確認できません" case zipCodeBrank = "郵便番号を入力してください" case zipCodeLengthNot7 = "郵便番号は7桁で入力してください" } private func validate(zipCode: String?){ guard let zipCode = zipCode else { self.showAlert(error: .zipCodeNil); return } if zipCode == "" { self.showAlert(error: .zipCodeBrank); return } if zipCode.lengthOfBytes(using: .utf8) != 7 { self.showAlert(error: .zipCodeLengthNot7); return } } private func showAlert(error: ErrorType) { let alert = UIAlertController(title: "検索に失敗しました", message: error.rawValue, preferredStyle: .alert) let action = UIAlertAction(title: "OK", style: .default, handler: nil) alert.addAction(action) self.present(alert, animated: true, completion: nil) } private func requestAPI(url:String,parameters:[String:Any],headers:HTTPHeaders) { AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: headers).responseJSON { response in guard let data = response.data else { return } do { try self.parse(data: data) } catch let error { print("Error: \(error)") self.showError() } } } private func parse(data:Data) throws { self.addresses = try JSONDecoder().decode(AddressModel.self, from: data) if let address = self.addresses { self.show(result: "\(address.results[0].address1) \(address.results[0].address2) \(address.results[0].address3)") } } private func show(result:String){ resultLabel.text = result } private func showError(){ resultLabel.text = "検索結果が取得できませんでした" } }参考資料
- 投稿日:2020-11-21T22:05:09+09:00
非同期処理について
同期処理と非同期処理の基本
同期処理とは
あるタスクを順番に実行する方式で、そのタスクが実行されている間は他のタスクが中断される
非同期処理とは
ある処理を実行する間に他の処理を実行できる
DispatchQueueとは
GCD(Grand Central Dispatch)の一部
DispatchQueueないにタスクを詰めると非同期で実行してくれるDispatchQueue自体には、
Serial、Concurrent、mainの3種類がある。DispatchQueue.main
OS側で作成済みなので呼び出すだけ。
1つだけ存在。
直列処理タイプ。
UI表示系タスクはここで行わないと動かない。viewController.swiftlet mainQueue = DispatchQueue.mainDispatchQueue.Global
OS側で作成済みなので呼び出すだけ。
5つ存在。(ただし、実質使えるのは4つ)
並列処理タイプ。
用途を指定して呼出し。viewController.swift// UserInteractiveタイプ let grobalQueue = DispatchQueue.global(qos: .userInteractive)sync
viewController.swiftdispatchQueue.sync { print("同期") }async
viewController.swiftdispatchQueue.async { print("非同期") }
- 投稿日:2020-11-21T22:05:09+09:00
同期、非同期処理について
同期処理と非同期処理の基本
同期処理とは
あるタスクを順番に実行する方式で、そのタスクが実行されている間は他のタスクが中断される
非同期処理とは
ある処理を実行する間に他の処理を実行できる
DispatchQueueとは
GCD(Grand Central Dispatch)の一部
DispatchQueueないにタスクを詰めると非同期で実行してくれるDispatchQueue自体には、
Serial、Concurrent、mainの3種類がある。DispatchQueue.main
OS側で作成済みなので呼び出すだけ。
1つだけ存在。
直列処理タイプ。
UI表示系タスクはここで行わないと動かない。viewController.swiftlet mainQueue = DispatchQueue.mainDispatchQueue.Global
OS側で作成済みなので呼び出すだけ。
5つ存在。(ただし、実質使えるのは4つ)
並列処理タイプ。
用途を指定して呼出し。viewController.swift// UserInteractiveタイプ let grobalQueue = DispatchQueue.global(qos: .userInteractive)sync
viewController.swiftdispatchQueue.sync { print("同期") }async
viewController.swiftdispatchQueue.async { print("非同期") }
- 投稿日:2020-11-21T17:52:08+09:00
キーボードタイプの種類とコード
はじめに
キーボードタイプの書き方や種類一旦ここにまとめようかなと思います。
定義
UIKeyboardTypeの定義をJump to Definition(コマンドキーを押しながら調べたいところをクリック)で調べてみました。
以下の通りです。public enum UIKeyboardType : Int { case `default` = 0 // Default type for the current input method. case asciiCapable = 1 // Displays a keyboard which can enter ASCII characters case numbersAndPunctuation = 2 // Numbers and assorted punctuation. case URL = 3 // A type optimized for URL entry (shows . / .com prominently). case numberPad = 4 // A number pad with locale-appropriate digits (0-9, ۰-۹, ०-९, etc.). Suitable for PIN entry. case phonePad = 5 // A phone pad (1-9, *, 0, #, with letters under the numbers). case namePhonePad = 6 // A type optimized for entering a person's name or phone number. case emailAddress = 7 // A type optimized for multiple email address entry (shows space @ . prominently). @available(iOS 4.1, *) case decimalPad = 8 // A number pad with a decimal point. @available(iOS 5.0, *) case twitter = 9 // A type optimized for twitter text entry (easy access to @ #) @available(iOS 7.0, *) case webSearch = 10 // A default keyboard type with URL-oriented addition (shows space . prominently). @available(iOS 10.0, *) case asciiCapableNumberPad = 11 // A number pad (0-9) that will always be ASCII digits. public static var alphabet: UIKeyboardType { get } // Deprecated }種類
種類は合計13種類あるみたいです。
- default
- asciiCapable
- numbersAndPunctuation
- URL
- numberPad
- phonePad
- namePhonePad
- emailAddress
- decimalPad
- webSearch
- asciiCapableNumberPad
- alphabet
実装方法
TextFieldをアウトレットで接続して、viewDidLoadで表示のコードを書きます。
.以降を変更してそれぞれのキーボードタイプを見ていきます。import UIKit class ViewController: UIViewController { @IBOutlet var textField1: UITextField! @IBOutlet var textField2: UITextField! @IBOutlet var textField3: UITextField! @IBOutlet var textField4: UITextField! @IBOutlet var textField5: UITextField! @IBOutlet var textField6: UITextField! @IBOutlet var textField7: UITextField! @IBOutlet var textField8: UITextField! @IBOutlet var textField9: UITextField! @IBOutlet var textField10: UITextField! @IBOutlet var textField11: UITextField! @IBOutlet var textField12: UITextField! @IBOutlet var textField13: UITextField! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. self.textField1.keyboardType = .default self.textField2.keyboardType = .asciiCapable self.textField3.keyboardType = .numbersAndPunctuation self.textField4.keyboardType = .URL self.textField5.keyboardType = .numberPad self.textField6.keyboardType = .phonePad self.textField7.keyboardType = .namePhonePad self.textField8.keyboardType = .emailAddress self.textField9.keyboardType = .decimalPad self.textField10.keyboardType = .twitter self.textField11.keyboardType = .webSearch self.textField12.keyboardType = .asciiCapableNumberPad self.textField13.keyboardType = .alphabet } }実装結果
最後に
13種類もあるなんて知りませんでした。
状況に合わせて使いこなせるようにしたいですね!
- 投稿日:2020-11-21T15:33:45+09:00
Develop in Swift Data CollectionsでiOS開発を学ぶ (1): Lesson 1.2まで
※(1)とついてますが続くかは不明
Develop in Swift Data Collectionsとは
Appleが高校生や大学生向けに出している学習用教材に含まれる、勉強用のドキュメントです。
https://www.apple.com/tr/education/docs/develop-in-swift-curriculum-guide.pdf
学生向け学習用カリキュラムがあり、そのカリキュラムの最終段階で学ぶ内容のようです。難しそうですが、まぁ現役のプログラマーならいけるでしょう(多分)。
この本を見つつ、iOS開発について学んでいく、という記事になります。基本は本を読んで、僕の記事はあくまで参考程度に見てもらえると良いと思います。
本自体はApple Booksから無料でダウンロードできます。
https://books.apple.com/jp/book/develop-in-swift-data-collections/id1511183970
前提知識・環境
もちろんMacが必要です。サンプルコードはXcode11のようですが、最新のM1搭載Mac上のXcode12でもサンプルコードは動きそうな気配がしてます(まだ全部のソースコードを動かしたわけではないですが)。
あた先ほど貼ったカリキュラム通り、Swfitの基本的な書き方とかは知っている前提の本になっていると思われます。
サンプルコードのダウンロード
8ページ目にサンプルコードをまとめたzipファイルへのリンクが貼ってあり、ここからダウンロードすることができます。
すべてのレッスンのサンプルコードが含まれている、というわけではなさそうです。
やってみる
Unit 1: Tables And Persistence
章のタイトルが?って感じなのですが、この章を終えると情報の表示と変数、保存のUIを構築できるようになるようです。
“By the end of this unit, you'll be comfortable building many useful apps that display all kinds of information and that allow users to enter, edit, and save in-app information.”
抜粋:: Apple Education “Develop in Swift Data Collections”。 Apple Inc. - Education、2020年 Apple Books https://books.apple.com/jp/book/develop-in-swift-data-collections/id1511183970
Lesson 1.1: Protocols
プロトコル(他の言語で言うとinterface)の話がずっと続きます。いきなりプロトコルの話からはじまるのが結構ガチだなという気がしますが、iOSアプリ開発においてはすごい基礎的で重要なことなんでしょうね。
この本は、一通り読み終わった後、章末問題的なものが用意されています。
いやーすごいですね。Apple Booksこんなこともできるんだ。
Lesson 1.2: App Anatomy and Life Cycle
アプリケーションのライフサイクルとAppDelegate/SceneDelegateの話が出てきます。
この節は実際にコードを組んでみるという実験(本では
Lab
と読んでいるようなので)があるのでやってみます。実験はアプリケーションのライフサイクルの動きを観察するものです。雛形は本のサンプルコード集に含まれていないようなので、Xcodeで新しく作成します。
で、コードを記述していきます。
1. AppDlegateにカウンタ変数を追加
下記の2つのメソッドの呼び出し回数をカウントできるようにコードを追加します。最終的に下記のようになると思います。
- application(_:didFinishLaunchingWithOptions:)
- application(_:configurationForConnecting:options:)
@main class AppDelegate: UIResponder, UIApplicationDelegate { var launchCount = 0 var configurationForConnectingCount = 0 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { launchCount += 1 return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { configurationForConnectingCount += 1 return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { } }2. ViewControllerに表示用のラベルを追加
Main.storyboardを開き、下記のようにラベルを追加していきます。
普通にlabelを置いていっても良いと思いますし、StackView内に積んで行っても良いと思います。
僕はこのQiitaの記事を参考にVertical StackViewを配置して、その中にラベルを置いていきました。そしてAutoLayoutで上下左右を端っこにピン留め。
Main.storyboardを作った後は、ViewController.swiftにそれぞれのラベルをアウトレットとして繋いで行きます。アウトレットというのは、要するにStoryboard上のUIパーツへの参照です。
@IBOutlet weak var didFinishLaunchingWithOptionsLabel: UILabel! @IBOutlet weak var configurationForConnectingLabel: UILabel! @IBOutlet weak var willConnectToLabel: UILabel! @IBOutlet weak var didBecomeActiveLabel: UILabel! @IBOutlet weak var willResignActiveLabel: UILabel! @IBOutlet weak var willEnterForegroundLabel: UILabel! @IBOutlet weak var didEnterBackgroundLabel: UILabel!そして、それぞれのラベルに表示させるカウンタ変数を作成します。
var willConnectToCount = 0 var didBecomeActiveCount = 0 var willResignActiveCount = 0 var willEnterForegroundCount = 0 var didEnterBackgroundCount = 03. AppDelegateの変数にViewControllerからアクセスする
SceneDelegateのカウンタ変数はViewController内にあるのですが、AppDelegateのカウンタ変数はAppDelegate内にあります(多分AppDelegateの方が生存期間が長いから?)
なので、それにアクセスできるようにする必要があります。
ViewControllerに下のように書けばアクセスできるようです。
var appDelegate = (UIApplication.shared.delegate as! AppDelegate)そして、それぞれのラベルを更新するupdateViewメソッドをViewControllerに作成します。
func updateView() { didFinishLaunchingWithOptionsLabel.text = "didFinishLaunchingWithOptions called \(appDelegate.launchCount) time(s)" configurationForConnectingLabel.text = "configurationForConnection called \(appDelegate.configurationForConnectingCount) time(s)" willConnectToLabel.text = "willConnectTo called \(willConnectToCount) time(s)" didBecomeActiveLabel.text = "didBecomeActive called \(didBecomeActiveCount) time(s)" willResignActiveLabel.text = "willResiginActive called \(willResignActiveCount) time(s)" willEnterForegroundLabel.text = "willEnterForeground called \(willEnterForegroundCount) time(s)" didEnterBackgroundLabel.text = "didEnterBackground called \(didEnterBackgroundCount) time(s)" }4. SceneDelegateからViewControllerにアクセスする
SceneDelegateのカウンタ変数はViewControllerにあるので、SceneDelegateからViewControllerのカウンタ変数を操作する必要があります。
メンバ変数としてviewControllerを宣言し、
var viewController: ViewController?willConnectToでwindowから取れば良いようです。
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { ... viewController = window?.rootViewController as? ViewController ... }5. SceneDelegateでカウンタ変数を更新する
viewControllerにSceneDelegateからアクセスできるようになったので、カウンタ変数を更新します。最終的にSceneDelegateは下記のようになると思います。
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var viewController: ViewController? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let _ = (scene as? UIWindowScene) else { return } viewController = window?.rootViewController as? ViewController viewController?.willConnectToCount += 1 } func sceneDidDisconnect(_ scene: UIScene) { } func sceneDidBecomeActive(_ scene: UIScene) { viewController?.didBecomeActiveCount += 1 viewController?.updateView() } func sceneWillResignActive(_ scene: UIScene) { viewController?.willResignActiveCount += 1 } func sceneWillEnterForeground(_ scene: UIScene) { viewController?.willEnterForegroundCount += 1 } func sceneDidEnterBackground(_ scene: UIScene) { viewController?.didEnterBackgroundCount += 1 } }6. updateViewを適切なタイミングで呼ぶ
カウンタ変数を更新しても、それをviewに反映させないと見ることはできません。
ViewControllerのupdateViewを適切なタイミングで呼ぶ必要があります。
SceneDelegateでは、先ほど貼ったコードで必要なタイミングで呼び出せています。あとはViewControllerのviewDidLoadで呼べばオッケーです。
最終的にViewControllerは下記のようになると思います。
class ViewController: UIViewController { @IBOutlet weak var didFinishLaunchingWithOptionsLabel: UILabel! @IBOutlet weak var configurationForConnectingLabel: UILabel! @IBOutlet weak var willConnectToLabel: UILabel! @IBOutlet weak var didBecomeActiveLabel: UILabel! @IBOutlet weak var willResignActiveLabel: UILabel! @IBOutlet weak var willEnterForegroundLabel: UILabel! @IBOutlet weak var didEnterBackgroundLabel: UILabel! var willConnectToCount = 0 var didBecomeActiveCount = 0 var willResignActiveCount = 0 var willEnterForegroundCount = 0 var didEnterBackgroundCount = 0 var appDelegate = (UIApplication.shared.delegate as! AppDelegate) override func viewDidLoad() { super.viewDidLoad() updateView() } func updateView() { didFinishLaunchingWithOptionsLabel.text = "didFinishLaunchingWithOptions called \(appDelegate.launchCount) time(s)" configurationForConnectingLabel.text = "configurationForConnection called \(appDelegate.configurationForConnectingCount) time(s)" willConnectToLabel.text = "willConnectTo called \(willConnectToCount) time(s)" didBecomeActiveLabel.text = "didBecomeActive called \(didBecomeActiveCount) time(s)" willResignActiveLabel.text = "willResiginActive called \(willResignActiveCount) time(s)" willEnterForegroundLabel.text = "willEnterForeground called \(willEnterForegroundCount) time(s)" didEnterBackgroundLabel.text = "didEnterBackground called \(didEnterBackgroundCount) time(s)" } }7. 動作確認
ここまでやったら動くようになっているので、実際にシミュレーターで動かします。動かした時の様子をgifで貼っておきます。
- 投稿日:2020-11-21T13:55:54+09:00
Xcode, Pods ProjectName.debug.xcconfig unable to open file.に対する対応方法
はじめに
Githubからcloneしたプロジェクトの実行を試みた際に
ProjectName.debug.xcconfig unable to open file
というエラーに遭遇したため備忘録をかねて記録として残したいと思います。以下のようにしていただければ解決できるかと存じます。
solvedpod deintegrate pod install今回参考にした記事です。
より詳細に記載がりますので、よろしければご参照ください。
https://stackoverflow.com/questions/55558984/xcode-pods-projectname-debug-xcconfig-unable-to-open-file-wrong-directoryご参考になれば幸いです。
- 投稿日:2020-11-21T13:04:25+09:00
iOSアプリでOSで提供する機能のUI言語の切り替え
- 投稿日:2020-11-21T02:55:36+09:00
【SwiftUI】TabViewとListの実装とViewのフォルダ管理
はじめに
SwiftUIでTabViewを作成し、それぞれのTabItemごとにViewを作る。
HomeViewにはListを表示し、前回作成したカード型のRowを呼び出すことを目的とする。UIのデザインはcakesのnote風のデザインを参考にViewを作ります。
今後は今回作成したカードに前回までに実装した地図と都道府県市町村名を表示できるようにし、Firebaseで更新できるようにすることが目的です。
前回までの記事は以下を参考ください。参考記事
【SwiftUi】経過時間の表示とListViewのセルデザイン開発環境
OSX 10.15.7 (Catalina)
Xcode 12.2.0
CocoaPods 1.10.0TabViewの作成とフォルダ管理
それぞれのViewはグループにまとめます。
大本のルートになるViewはContentViewです。
ContentViewの記載内容は以下のとおりです。import SwiftUI struct ContentView: View { var body: some View { // TabBarViewの呼び出し TabBarView() } }ContentviewではTabBarViewの呼び出しのみを行い、TabBarViewではHomeやSearch、Post、Info、AccountのそれぞれのViewを呼び出します。
import SwiftUI struct TabBarView: View { var body: some View { TabView { // HomeView NavigationView{ // HomeViewの呼び出し Home() .navigationBarTitle("ホーム", displayMode: .inline) }.tabItem { Image(systemName: "house.fill") .font(.title) Text("ホーム") } // SearchView NavigationView{ // SearchViewの呼び出し Search() .navigationBarTitle("みつける", displayMode: .inline) } .tabItem { Image(systemName: "map.fill") .font(.title) Text("マップ") } // PostView Text("Post") .tabItem { Image(systemName: "plus.circle.fill") .font(.title) Text("詠む") } // InfomationView NavigationView{ // InfoViewの呼び出し Info() .navigationBarTitle("おしらせ", displayMode: .inline) } .tabItem { Image(systemName: "info.circle.fill") .font(.title) Text("おしらせ") } // AccountView NavigationView{ // AccountViewの呼び出し Account() .navigationBarTitle("アカウント", displayMode: .inline) } .tabItem { Image(systemName: "person.fill") .font(.title) Text("アカウント") } } .accentColor(Color("pinkColor")) } }HomeViewにListを実装する
前回記事で作成したRowを呼び出します。
参考記事
【SwiftUi】経過時間の表示とListViewのセルデザイン本来なら、ここのRow部分はFirebaseからデータベースを呼び出し更新できるように実装しますが、まだ実装できていないため、今回は同じ記事を出力しています。
また、今後はスクロールした際に記事を自動でロードできるようにする予定です。
今回はListの出力の様子のみ確認します。import SwiftUI struct Home: View { var body: some View { List { ForEach(0..<8){_ in ContentRowView() .listRowInsets(EdgeInsets()) } } } }Simulatorで確認したところ、スムーズにスクロールができました。
また、navigationBarTitleもスクロールしても表示され続けているため、意図したとおりに実装できました。できれば、ListのRowごとに出力されるボーターの左側の余白を消したいけど、実装の仕方を見つけられなかったため、次回修正します。
今後実装予定のもの
・HomeViewのList内のRow部分をFireBaseから更新できるようにする。
・Search、Post、Info、AccountのそれぞれのViewを実装する。以上です。
- 投稿日:2020-11-21T02:55:36+09:00
【SwiftUi】TabViewとListの実装とViewのフォルダ管理
はじめに
SwiftUIでTabViewを作成し、それぞれのTabItemごとにViewを作る。
HomeViewにはListを表示し、前回作成したカード型のRowを呼び出すことを目的とする。UIのデザインはcakesのnote風のデザインを参考にViewを作ります。
今後は今回作成したカードに前回までに実装した地図と都道府県市町村名を表示できるようにし、Firebaseで更新できるようにすることが目的です。
前回までの記事は以下を参考ください。参考記事
【SwiftUi】経過時間の表示とListViewのセルデザイン開発環境
OSX 10.15.7 (Catalina)
Xcode 12.2.0
CocoaPods 1.10.0TabViewの作成とフォルダ管理
それぞれのViewはグループにまとめます。
大本のルートになるViewはContentViewです。
ContentViewの記載内容は以下のとおりです。import SwiftUI struct ContentView: View { var body: some View { // TabBarViewの呼び出し TabBarView() } }ContentviewではTabBarViewの呼び出しのみを行い、TabBarViewではHomeやSearch、Post、Info、AccountのそれぞれのViewを呼び出します。
import SwiftUI struct TabBarView: View { var body: some View { TabView { // HomeView NavigationView{ // HomeViewの呼び出し Home() .navigationBarTitle("ホーム", displayMode: .inline) }.tabItem { Image(systemName: "house.fill") .font(.title) Text("ホーム") } // SearchView NavigationView{ // SearchViewの呼び出し Search() .navigationBarTitle("みつける", displayMode: .inline) } .tabItem { Image(systemName: "map.fill") .font(.title) Text("マップ") } // PostView Text("Post") .tabItem { Image(systemName: "plus.circle.fill") .font(.title) Text("詠む") } // InfomationView NavigationView{ // InfoViewの呼び出し Info() .navigationBarTitle("おしらせ", displayMode: .inline) } .tabItem { Image(systemName: "info.circle.fill") .font(.title) Text("おしらせ") } // AccountView NavigationView{ // AccountViewの呼び出し Account() .navigationBarTitle("アカウント", displayMode: .inline) } .tabItem { Image(systemName: "person.fill") .font(.title) Text("アカウント") } } .accentColor(Color("pinkColor")) } }HomeViewにListを実装する
前回記事で作成したRowを呼び出します。
参考記事
【SwiftUi】経過時間の表示とListViewのセルデザイン本来なら、ここのRow部分はFirebaseからデータベースを呼び出し更新できるように実装しますが、まだ実装できていないため、今回は同じ記事を出力しています。
また、今後はスクロールした際に記事を自動でロードできるようにする予定です。
今回はListの出力の様子のみ確認します。import SwiftUI struct Home: View { var body: some View { List { ForEach(0..<8){_ in ContentRowView() .listRowInsets(EdgeInsets()) } } } }Simulatorで確認したところ、スムーズにスクロールができました。
また、navigationBarTitleもスクロールしても表示され続けているため、意図したとおりに実装できました。できれば、ListのRowごとに出力されるボーターの左側の余白を消したいけど、実装の仕方を見つけられなかったため、次回修正します。
今後実装予定のもの
・HomeViewのList内のRow部分をFireBaseから更新できるようにする。
・Search、Post、Info、AccountのそれぞれのViewを実装する。以上です。