[ SwiftUI ][ Mapbox ] iOS アプリ で Mapbox 地図に マーカー ピン を立てる

eye-catch

関連する 前回の記事で SwiftUI を使って iOS 上に Mapbox の地図を表示することができたので、次の ステップ として地図に マーカー (ピン) を立てて、特定の地点を指し示すようにしてみたいと思います。 Xcode: 13.2.1 iOS: 15.2 Swift: 5.5 mapbox-maps-ios: v10.2.0 Mapbox 公式 ドキュメント の説明 Mapbox 公式 ドキュメント には Example として、以下のように コペンハーゲン に マーカー を表示する サンプル が掲載されています。まずは、その サンプル の内容を確認していくことにします。 引用元: https://docs.mapbox.com/ios/maps/examples/point-annotation/ UIViewController 前回の記事同様、 公式 サイト で提供されているのは UIViewController のものですので、 SwiftUI で扱うためには UIViewControllerRepresentable を用いる必要があります。 考え方は前回の記事と同様ですので、詳細については前回の記事を参考にしてください。 MapBox MapView の生成 サンプル で紹介されている ViewController では最初に マップ の中心を指定し、 マップ を生成しています。 ただし、このままでは マップ を表示することができないため、以下のように修正していきます。 ”Your Access Token” には有効な アクセストークン を指定してください。 myResourceOptions として アクセストークンをセット MapInitOptions に resourceOptions パラメータ を追加 ここで、いくつか馴染みの薄そうな アイテム について補足していきます。 CLLocationCoordinate2D CLLocationCoordinate2D は 緯度  と 経度 を パラメータ として生成する位置情報のオブジェクトです。今回の例では マップ の中心座標として利用しています。 MapInitOptions ResourceOptions として accessToken を指定したり、 CameraOptions として 中心座標や縮尺などを指定した マップ 生成時の オプション 用 オブジェクト です。  cameraState … Read more

[SwiftUI] Mapbox の地図を Maps SDK for iOS を用いて実装する – 実装編

前回の記事 で環境準備が整いましたので、早速 Mapbox の地図 を SwiftUI で実装していきたいと思います。 Maps SDK for iOS を用いて実装してきますので、 Maps SDK for iOS の インストール ができていない場合は 前回の記事 を参考に インストール した後に本記事を参照ください。 Mapbox 公式 サイト が提供している サンプルコード は そのままでは SwiftUI に組み入れることができないため UIViewRepresentable を活用して実装していますので、 UIViewRepresentable についても簡単に解説しながら進めていきます。 Xcode: 13.2.1 iOS: 15.2 Swift: 5 Maps SDK for iOS: v10.2.0 公式 サイト で紹介されている Maps SDK for iOS サンプル コード Mapbox の公式サイト には 簡単な サンプル が紹介されているのですが、 残念ながら SwiftUI を用いた そのものズバリのものは紹介されておらず、 UIViewController を用いたもののみが紹介されています。 UIViewController は iOS 2.0 以降で実装可能な “枯れた” 技術ではありますが、 SwiftUI で実装するためには UIViewRepresentable を用いてひと手間加える必要があります。 UIViewRepresentable について Apple Developer サイト によると UIViewRepresentable は以下のように紹介されています。 A wrapper for a UIKit view that you use to integrate that view into your SwiftUI view hierarchy. https://developer.apple.com/documentation/swiftui/uiviewrepresentable つまり、iOS 2.0 以降 サポート … Read more

[SwiftUI] Mapbox の地図を Maps SDK for iOS を用いて実装する – 環境準備編

こちらの記事 で SwiftUI を用いて Apple 純正の Map を iOS アプリ で活用する方法を紹介しました。 ただし、 SwiftUI はまだまだ発展途上な部分も多く、 2021 年時点では 実現できることは限られています。 そこで 外部の 地図 サービス である MapBox の Maps SDK for iOS を用い SwiftUI で地図を実装する方法について 「環境準備編」「実装編」の 2 回に分けて説明していきたいと思います。 Xcode: 13.2.1 iOS: 15.2 Swift: 5 Maps SDK for iOS: v10.2.0 環境準備編 では 以下を実施していきます。 Xcode プロジェクト作成 Access Token の作成 Xcode 環境設定 SwiftUI プロジェクト 作成 最初に 本記事で使用する Xcode プロジェクト を作成していきます。プロジェクト 新規作成画面から App を選択し、 “mapbox-sample” という名称で プロジェクト を作成します。  このプロジェクト を使って クイックスタート を進めていきたいと思います。 次に 地図の表示など Mapbox API の各機能 に アクセス するために必要な Access Token を作成してきます。 Mapbox で用いる Access Token の作成 Maps SDK for iOS などの Mapbox SDK を介して Mapbox の各機能を利用する際には 認証情報として Mapbox アカウント に紐付いた Access Token が必要になります。 まずは Access Token について簡単に整理しておきます。 … Read more

SwiftUI で Apple 地図 ( Maps ) を実装する方法 – ピン を 複数 立てる方法 等 –

スマホ アプリ の強みとして「 地図 の表示」や 「場所に ピン を立てること」 が挙げられると思います。 SwiftUI を用いて実装できる 地図 サービス には いくつかの種類がありますが 本記事では Apple 純正の Map を取り上げ、 SwiftUI を用いて 以下を実装する方法について説明していきます。 緯度経度情報を基に 地図 を表示する方法 1 つの ピン を立てる方法 複数 ピン を立てる方法 Xcode: 13.1 iOS: 14.5 Swift: 5 緯度経度を基に 地図 を表示 まずはじめに 緯度経度を基に地図を表示してみたいと思います。 Apple Developer サイト の情報 に従って Apple Park の地図を表示してみます。 MapKit を インポート @State 変数 として MKCoordinateRegion 型の変数 region を作成 MKCoordinateRegion は 以下を引数にもつ 引数 説明 center 中心地点を CLLocationCoordinate2D を 緯度経度 を基に指定 latitudinalMeters 地図に表示する 南北方向の広さを メートル で指定 longitudinalMeters 地図に表示する 東西方向の広さを メートル で指定 Map オブジェクト には 上述した region 変数を引数に指定 ContentView で この View (AppleParkMap) を呼び出す形にして ビルド してみると以下のような結果となります。 コード 上は 東西 南北 共に 750 m としていますが、縦長の画面に表示するため、 南北 750 m として表示されます。 なお … Read more

[ SwiftUI ] タイムゾーン を意識した 日付, 時刻 文字列 を 扱う方法

Swift に限った話ではありませんが、 日付 や 時刻 を扱う際に、特定の地域のみを対象にする場合は タイムゾーン や 時差 を意識することはありませんが、 グローバル な ユーザ を対象とする場合は、 ユーザ の ローカル 時間帯 を意識することがユーザの利便性向上につながります。 本記事では、 UTC で表現された 日付文字列 を タイムゾーン を意識しながら管理し、 別の タイムゾーン で表示する方法について整理していきます。 Xcode: 13.0 iOS: 14.5 Swift: 5 今回実現すること 今回は、 “2021-10-06T18:45:00+00:00” という UTC で表現された文字列を扱い、これを様々なタイムゾーンで表示してみます。。例えば JST の場合、 UTC に +9 時間足した 2021年10月7日 3:45 AM と表示することを目指します。 Timezone の表示 まずは百聞は一見にしかずということで、 「 現在時刻 」 と 「 現在の タイムゾーン 」 を表示する View を作成して内容をみてみます。 システムの設定を 日本 としているため、 以下のような結果となっています。 Locale: Japan Standard Time (JST) Timezone: GMT+9 システム の設定を ロンドン に変更するとこの内容が変化していきます。 Locale: British Summer Time (BST) Timezone: GMT+1 以降では、このように 文字列 を タイムゾーン を意識して扱い、 ユーザ が所属する タイムゾーン 別に表示を変更する方法を整理していきます。 日付文字列 を Date 型に変換 @State 変数の用意 それでは、日付文字列 を Date 型に変換していきます。最初に、アプリ上で 文字列や フォーマット の指定可能にするため、  @State … Read more

GCP Cloud Functions チュートリアル 解説

本記事では、 GCP Cloud Functions チュートリアル を実際に進めていきながら、初心者の方でもわかりやすいように、公式 サイト での説明が少し不足している部分などを中心に補足しながら、実際に進めていきます。なお、以前ご紹介したとおり、 Google が提供する Serverless Computing には、以下の2種類が存在します。 サーバサイド に フォーカス した、 GCP Cloud Functions モバイルデバイス に フォーカス した、 Cloud Functions of Firebase 今回の一連の投稿では、「 サーバサイド に フォーカス した、 GCP Cloud Functions 」の実装を、 チュートリアル の内容に沿って進めていきます。なお、関数の記述には Python を使うことにします。 なお、公式サイト上は「 クイックスタート 」や「 入門ガイド 」といった表現が使われていますが、本ブログではすべて「 チュートリアル 」として表現させていただきます。 チュートリアル サイト https://cloud.google.com/functions/docs/quickstarts?hl=ja シリーズ 記事一覧 チュートリアル 概要 事前準備(1) プロジェクト作成、課金有効化 事前準備(2) API 有効化、その他(認証情報について) Pythonクイックスタート Pythonで記載した簡単な関数をデプロイする。事前準備として、プロジェクト の作成、課金の有効化、 API の有効化が必要。 最初の関数: Python Python クイックスタート が GCP 上で全て完結していたのに対し、こちらは、 ローカル の開発環境で、 Cloud SDK を用いて Cloud Functions を開発する チュートリアル になっています チュートリアル一覧

[SwiftUI] 日付 文字列を SwiftUI の Date 型に変換する

SwiftUI において、日付 の形式で記述された 文字列を Date 型として扱う際には DateFormatter を用いて 型変換 をすると便利です。今回は、実際に画面上で 文字列 , フォーマット , ロケール を指定しながら内部でどのように取り扱われているのかを サンプル コード とともに見ていきます。 Swift 5, Xcode 12.5.1 はじめに SwiftUI において、文字列を日付型( Date )に変換するには DateFormatter を用いるところまではすんなり理解できたのですが、実際の サンプル をあまり発見できず モヤモヤ していたので実際に サンプル コード を作って確かめてみました。 日付文字列 -> Date() 変換 入力 フィールド の準備 まずは、 入力 フィールド を TextField を用いて作成していきます。変換したい日付の文字列 (dateString) とその文字列がどのような形式であるか (dateFormat) を用意します。 とりあえず、 入力 フィールド には初期値として適当な値を設定しておきます。 日付文字列 -> Date 型変換 処理の実装 次に、Date 型への変換処理部分を作成します。 最初に確認用に TextField に入力された値を出力した後、 DateFormatter() を用いて初期化した変数を作成します。この変数に、本画面に設定されている日付の フォーマット をdateFormatとして登録します。日付文字列の内容を dateFormatter.date を用いてdate 変数に格納し、そのdate変数の内容を出力しています。 合わせて、初期処理と各入力値の変更を リアルタイム に反映する処理を VStack の モディファイア として追記します。 上記で作成できる画面は以下のようになります。必要な情報をこの画面で入力し、出力結果は上述の通り、 Xcode 内の デバッグ ウィンドウ に表示させる仕組みとなっています。 それでは、実際に動かしてみます。 日付文字列 -> Date 型変換 処理 の実行 まずは、 コード に直接記載した デフォルト 値での出力をみていきます。 入力した日付と、 Date() に変換した日付が異なっていますが、これは プログラム 実行環境が JST(UTC +9) の環境で実施していたことが影響しています。 時刻を入力していないため、時刻が補完された、”2020年12月31日0時0分という文字列”を、”指定された ロケール … Read more

[SwiftUI]Webアクセスの仕組み – URL Loading System

以下の投稿でWeb上のAPIからデータを取得する部分のサンプルコードをご紹介しましたが、そもそものSwiftUIがWebにアクセスする仕組みについて正しく理解をしたいと思いましたので、本投稿で整理したいと思います。 URL Loading System SwiftUIにおいてインターネット通信を行う際にはこの仕組みを用いることになります。 You use a URLSession instance to create one or more URLSessionTask instances, which can fetch and return data to your app, download files, or upload data and files to remote locations.  https://developer.apple.com/documentation/foundation/url_loading_system 上記にあるように、URLSessionを一つ作成し、その配下にURLSessionTaskを1つ以上作成する、というのが基本的なコンセプトのようです。以下の図がわかりやすそうです。 つまり、流れとしては以下のようになります。 URLSessionを作成 タスク毎にURLSessionTaskを作成 ここで、URLSession、URLSessionTaskについて概要を整理していきます。 URLSession URLSessionには以下のタイプがあるようです 基本的なリクエスト用のshared session(Configuration Objectを持たない) カスタマイズ可能な作成したsession(Configuration Objectを持つ)→ URLSessionConfigurationを活用 なお、公式ドキュメントでは、まずはConfiguration Objectを持たないshared sessionから始めることを推奨しています。これは、後述するshared sessionの利用方法が最もシンプルである、ということも大きな理由のようです。 URLSessionConfiguration ”カスタマイズ可能なsession”を作成する際にこちらを活用することになり、カスタマイズのパターンは以下の3つが用意されています。 Default session:delegateを用いた段階的なデータ取得が可能 Ephemeral session:キャッシュ、クッキー、認証情報をディスクに書き込まない Background session:アプリケーションが動作していないときの、バックグラウンドでのコンテンツのアップロードやダウンロードが可能 URLSessionTask URL Session Taskに関しては、4種類のタスクが用意されている旨、URLSessionのドキュメントに記載されています。 Data tasks: NSDataオブジェクトを使用してデータ送受信。ちょっとした(特にインタラクティブな)リクエスト向きタスク Upload tasks: バックグラウンドでのアップロードに対応した、ファイル送信向きタスク Download tasks: バックグラウンドでのダウンロード、アップロードに対応した、ファイル送受信向きタスク WebSocket tasks: RFC6455のWebSocketプロトコルを使った、TCP、TLSでのメッセージ交換向きタスク ファイルのアップロードだけであれば、Upload Task、ファイルのダウンロードも必要であれば、Download Taks、サーバからクライアントに対して更新のポーリングが必要であれば、WebSocket Task、それ以外であれば、Data Task、といった使い分けでしょうか。 RFC6455 https://triple-underscore.github.io/RFC6455-ja.html#section-1.1 task state URLSessionTaskは以下の4つの状態を持ち、タスクが生成された時点ではsuspended状態になるため、使用開始するためには、忘れずにresumeを用いてrunning状態にすることが重要です。状態別の概要は以下の通りです。 running: 現在実行中のタスク。タイムアウトの影響を受ける suspended: タスクが再開されるまで処理を行わない。タイムアウトにはならない canceling: cancelメッセージを受信したタスク。タイムアウトにはならない completed: cancel以外で完了したタスク。errorプロパティはnil。タイムアウトにはならない task resume Newly-initialized tasks begin in a suspended state, so you need to call this method to start … Read more

[SwiftUI]Web上のAPIからJSONデータを取得するサンプルコード

Xcode 12.4, Swift 5 SwiftUIを用いて、Web上で稼働しているAPIにアクセスしてJSON形式のデータを取得し、画面上に表示するサンプルコードを作成してみました。利用するAPIやデータ、表示するViewなども極力シンプルな形にしています。 API & Data 今回は、以下のサイトで公開されているAPIを使わせていただくことにします。Todo管理ツールを想定したデータとなっていて、ユーザID、ID、タイトル、完了フラグがセットとなったデータが複数格納されています。 https://jsonplaceholder.typicode.com/ 今回は、最もシンプルなデータを利用することにしますので、以下の形式でAPI実行して取得できるデータを対象にします。 https://jsonplaceholder.typicode.com/todos/1 Implementaion データ取得用のViewの作成 まずは、データを取得するViewを作成していきます。以下がポイントになります。 取得するデータ型(ToDoData)をJSONで取得する要素のそれぞれの型に合わせ(Int, Int, String, Bool)、Codableで定義 取得するデータ(todo)を@Stateで定義し、値の動的な変化に対応させる この状態のViewは以下のようになります。 GetDataボタンをタップすることで、その下の領域に取得したデータからタイトルを表示するようにしたいと思います。現状は、初期値である”na”が表示されています。 データ取得部分の作成 まずは、GetDataボタンをタップする部分を追加していきます。タップしたら、getData()を呼び出すかたちです。 次に、getData()の中身を作成していきます。 getDataの内容について、いくつかポイント(ハイライト部分)を説明します。 URLSession, Task 今回はシンプルな通信なので、shared sessionを使い、data taskを用いることにしているため上記の実装としています。 https://developer.apple.com/documentation/foundation/urlsession JSONDecoder JSONDecoder.decodeにJSONのデータ型であるTodoDataを渡しています。.selfを忘れず付与するようにしてください。JSONデコードについては以下の投稿も参考にしてください。 resume 新規に作成されたタスクはsuspended状態で始まるため、タスクを開始(使用)するためには、忘れずにresume()を用いる必要があります。実際、今回のコードからこの部分を削除するだけでも、データの取得ができなくなります。 https://developer.apple.com/documentation/foundation/urlsessiontask/1411121-resume Behavior 今回実装したコードを動かすと、以下のようになります。 まとめ 今回、これ以上シンプルにはできないレベルでサンプルコードを作成してみました。実際の用途ではデータ構造がより複雑だったりと、そのままでは使えないと思いますが、こういった小さなコードから始めることで理解が深まればと思います。 SwiftUIにおける、Webアクセスに関して以下で詳細に解説していますので、今回のサンプルコードがブラックボックスのように思える方は一読していただけると理解が深まるかもしれません。 サンプルコード

[SwiftUI]DisclosureGroup Examples

Xcode 12.4, Swift 5 SwiftUIで利用可能なDisclosureGroupについて簡単なサンプルを使って実際の動きをみていきます。公式ドキュメントでは「ディスクロージャーコントロールの状態に応じて、別のコンテンツビューを表示・非表示するビュー」とのことですが、実際の例を使ってみてみるのが理解が早そうです。 公式ドキュメント 公式ドキュメントを読み進めると、DisclosureGroupは以下の2つの要素から成り立っているようです。 ラベル:コンテンツを識別 コントロール:コンテンツを表示/非表示する まずは、これら2つを最もシンプルな形で実装してみます。 最小構成 最小構成のコードは以下のようになります。 左右いっぱいに広がったエリアの左端にラベルが表示され、右端に開閉用のアイコンが表示されています。この開閉用のアイコンをタップすることで、コンテンツとして指定したTextオブジェクトが中央に表示(非表示)されます。 isExpanded Initializer追加 次に、isExpanded Initializerを使ってみることにします。これを使うことでさきほどの開閉動作を制御することが可能になります。注意しなければいけないのが、このInitializerにはBindingを用いる必要がある点です。具体的な例を使ってみていきます。 このように、Bool型の@Stateプロパティを作成し、それを参照渡し($をつけて渡す)することでDisclosureGroupの開閉に合わせてBool値であるisExpandが変化することがわかります。初期値をtrueとしていますので、開いた状態を初期状態としています。 公式サイトに近い実践的な実装 最後に公式サイトに掲載されているサンプルに近いかたちで実装した際の振る舞いをみていきます。 Optionsを開くと、Toggleオブジェクトである、Option1とOption2が表示され、それぞれOn/Offを切り替えることができています。 まとめ iOSアプリ開発においては、このDisclosureGroupのようにうまく開閉をもちいて限られたスペースを有効活用することで柔軟なUIが設計できそうです。同じ”Group”を冠する、GroupBoxが表示面では秀でているようにも見えるためうまく組み合わせするとよささおうです。 References https://developer.apple.com/documentation/swiftui/disclosuregroup https://developer.apple.com/documentation/swiftui/binding/