モバイル チュートリアル:位置センサを使用する(iOS および Android)

提供: Appmethod Topics
移動先: 案内検索

モバイル チュートリアル:モバイル アプリケーション開発(iOS および Android) への移動


このチュートリアルを開始する前に、次のチュートリアルを読んで実行してください。

メモ: Android デバイスでは、TLocationSensor[おおよその位置情報へのアクセス]および[詳細な位置情報へのアクセス]権限を設定する必要があります。

このチュートリアルでは、(緯度と経度を使用して)モバイル デバイスの位置を確認し、逆ジオコーディングによって次の図のような人が読み取れる住所に変換します。


IOSLocationDemo.PNG

ユーザー インターフェイスの設計

このデモ アプリケーションの設計には、2 つの主要コンポーネントが含まれています。TListBox(左側)と TWebBrowser です。

メモ: この作業を進める前に、[プロジェクト マネージャ]で、アクティブなターゲット プラットフォームを[iOS デバイス]または[Android]に設定してください。そうでなければ TWebBrowser コンポーネントを追加できません。

DesignLocationDemo.png

  • TListBox の Align プロパティを Left に設定して、UI の左側を確保します。その後、リスト ボックスの下に次のサブコンポーネントを作成します。
    • 以下のサブコンポーネントを含む TListBoxHeader コンポーネント
      • タイトル "Location Demo" を表示するための TLabel コンポーネント
      • TLocationSensor のオン/オフを選択するための TSwitch(Switch1)コンポーネント
    • テキストが "Your Location" の TListBoxGroupHeader
    • 名前が "ListBoxItemLatitude"、テキストが "Latitude" の TListBoxItem
    • 名前が "ListBoxItemLongitude"、テキストが "Longitude" の TListBoxItem
    • テキストが "Current Address" の TListBoxGroupHeader
    • 名前が "ListBoxItemAdminArea"、テキストが "AdminArea" の TListBoxItem
    • 名前が "ListBoxItemCountryCode"、テキストが "CountryCode" の TListBoxItem
    • 名前が "ListBoxItemCountryName"、テキストが "CountryName" の TListBoxItem
    • 名前が "ListBoxItemFeatureName"、テキストが "FeatureName" の TListBoxItem
    • 名前が "ListBoxItemLocality"、テキストが "Locality" の TListBoxItem
    • 名前が "ListBoxItemPostalCode"、テキストが "PostalCode" の TListBoxItem
    • 名前が "ListBoxItemSubAdminArea"、テキストが "SubAdminArea" の TListBoxItem
    • 名前が "ListBoxItemSubLocality"、テキストが "SubLocality" の TListBoxItem
    • 名前が "ListBoxItemSubThoroughfare"、テキストが "SubThoroughfare" の TListBoxItem
    • 名前が "ListBoxItemThoroughfare"、テキストが "Thoroughfare" の TListBoxItem
  • Web ページ(Google マップ)を表示するための TWebBrowser コンポーネント(WebBrowser1)。Align プロパティを Client に設定します。

これらのコンポーネントを作成したら、すべての TListBoxItem 項目を選択し、StyleLookup プロパティに listboxitemleftdetail を選択します。これによって TListBoxItem にラベルと詳細テキストの両方が表示されます。

位置センサ

位置センサは、TLocationSensor コンポーネントにラップされています。

デバイスで移動が検出されると、TLocationSensorOnLocationChanged イベントが発生します。TLocationSensor の感度は Distance プロパティと Accuracy プロパティで調整することができます。

  • Distance プロパティは、位置センサにデバイスの位置を再検索させ、新しい位置情報を返させるために、デバイスが最低でも移動しなければならない距離(メートル単位)を示します。たとえば Distance を "10" に設定すると、"10 メートル" 移動したときに TLocationSensorOnLocationChanged イベントが発生します。
  • Accuracy プロパティは、センサが地理的にデバイスの位置を検索するときの、デバイスが実際に存在する地理的位置に対する精度(メートル単位)を表します。
ヒント: アプリケーションに必要な最低の精度を指定してください。精度が高くなればなるほど、センサによる位置の決定に必要な時間と処理能力が増えるからです。推奨値は、Distance=0、Accuracy=0 です。

位置センサ コンポーネントからの位置情報(緯度、経度)の読み取り

TLocationSensor コンポーネントをアクティブ化して使用できるようにしなければなりません。TSwitch コンポーネントや他のアプリケーション イベントなどの入力によって、TLocationSensor をオン/オフすることができます。

  1. [ツール パレット]から TLocationSensor コンポーネントを配置します。
  2. フォーム デザイナTSwitch コンポーネントを選択します。
  3. [オブジェクト インスペクタ][イベント]タブの OnSwitch イベントをダブルクリックします。
  4. OnSwitch イベント ハンドラに以下のコードを追加します。
Object Pascal の場合:
procedure TForm1.Switch1Switch(Sender: TObject);
begin
  LocationSensor1.Active := Switch1.IsChecked;
end;
C++ の場合:
void __fastcall TForm1::Switch1Switch(TObject *Sender)
{
        LocationSensor1->Active = Switch1->IsChecked;
}

先ほど述べたように、モバイル デバイスを動かすと、TLocationSensorOnLocationChanged イベントが発生します。イベント ハンドラでパラメータを使用して現在の位置(緯度と経度)を表示することができます。

  1. フォーム デザイナTLocationSensor を選択します。
  2. [オブジェクト インスペクタ][イベント]タブの OnLocationChange イベントをダブルクリックします。
  3. OnLocationChange イベント ハンドラに以下のコードを追加します。
Object Pascal の場合:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
  const OldLocation, NewLocation: TLocationCoord2D);
var
  LDecSeparator: String;
begin
  LDecSeparator := FormatSettings.DecimalSeparator;
  FormatSettings.DecimalSeparator := '.';
  // Show current location
  ListBoxItemLatitude.ItemData.Detail  := Format('%2.6f', [NewLocation.Latitude]);
  ListBoxItemLongitude.ItemData.Detail := Format('%2.6f', [NewLocation.Longitude]);
end;
C++ の場合:
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
                  const TLocationCoord2D &NewLocation)
{
        char LDecSeparator = FormatSettings.DecimalSeparator;
        FormatSettings.DecimalSeparator = '.';
        // Show current location
        ListBoxItemLatitude->ItemData->Detail = ListBoxItemLatitude->ItemData->Detail.sprintf(L"%2.6f", NewLocation.Latitude);
        ListBoxItemLongitude->ItemData->Detail = ListBoxItemLongitude->ItemData->Detail.sprintf(L"%2.6f", NewLocation.Longitude);
}

TWebBrowser コンポーネントで Google マップを使用した現在位置の表示

モバイル チュートリアル:Web ブラウザ コンポーネントを使用する(iOS および Android)」で説明しているように、TWebBrowser コンポーネントにはモバイル プラットフォーム用の Web ブラウザがラップされています。

次の URL パラメータを使用すると、TWebBrowser コンポーネントから Google マップを呼び出すことができます。

 https://maps.google.com/maps?q=(Latitude-value),(Longitude-value)

そのため、この URL を先ほど作成したイベント ハンドラ OnLocationChanged に追加します。コードは次のようになります。

Object Pascal の場合:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
  const OldLocation, NewLocation: TLocationCoord2D);
var
  URLString: String;
begin
  // code for previous step goes here

  // Show Map using Google Maps
  URLString := Format(
    'https://maps.google.com/maps?q=%s,%s',
      [Format('%2.6f', [NewLocation.Latitude]), Format('%2.6f', [NewLocation.Longitude])]);
  WebBrowser1.Navigate(URLString);
end;
C++ の場合:
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
                  const TLocationCoord2D &NewLocation)
{
        // code for previous step goes here

        // Show Map using Google Maps
        String LLongitude = FloatToStr(NewLocation.Longitude, FormatSettings);
        String URLString = "";
        URLString = URLString.sprintf(L"https://maps.google.com/maps?q=%2.6f,%2.6f",
                NewLocation.Latitude, NewLocation.Longitude);

        FormatSettings.DecimalSeparator = LDecSeparator;
        WebBrowser1->Navigate(URLString);
}

逆ジオコーディングの使用

TGeocoder は、ジオコーディング(または逆ジオコーディング)サービスをラップするオブジェクトです。

ジオコーディングとは、住所や郵便番号などの地理データを地理座標に変換する処理です。逆ジオコーディングとは、地理座標をそれ以外の住所などの地理データに変換する処理です。

ここでは、TGeocoder を使用して、位置(緯度と経度)を "逆ジオコーディング" し、人が読み取れる住所情報にします。

TGeocoder を使った作業の基本的な手順は次のとおりです。

  1. TGeocoder のインスタンスを作成します。
  2. イベント OnGeocodeReverse を定義して、後でイベントを受け取れるようにします。
  3. "逆ジオコーディング" を実行するためのデータを設定します。
  4. TGeocoder accesses the service on the network to resolve the address information.
  5. TGeocoderOnGeocodeReverse イベントが発生します。
  6. iOS アプリケーションで、OnGeocodeReverse イベントのパラメータから住所情報を受け取り、ユーザー インターフェイスを更新します。
メモ: TGeocoder はコンポーネントではないため(ただのクラスです)、これらの手順をコードで定義する必要があります(コンポーネントをドロップしたり[オブジェクト インスペクタ]でイベント ハンドラを割り当てることはできません)。

まず、フォームの private セクションに新しいフィールド "FGeocoder" を定義します。また、"OnGeocodeReverseEvent 手続き" も定義します。コードは次のとおりです。

Object Pascal の場合:
type
  TForm1 = class(TForm)
    // IDE defines visible (or non-visual) components here automatically
  private
    { Private declarations }
    FGeocoder: TGeocoder;
    procedure OnGeocodeReverseEvent(const Address: TCivicAddress);
  public
    { Public declarations }
  end;

C++ の場合:

メモ: このコード スニペットをヘッダー ファイル(.h)に入れます。
class TForm1 : public TForm
{
        // IDE defines visible (or non-visual) components here automatically
private:        // User declarations
        TGeocoder *FGeocoder;
        void __fastcall OnGeocodeReverseEvent(TCivicAddress* const Address);
public:         // User declarations
        __fastcall TForm1(TComponent* Owner);
};


これで、Object Pascal または C++ のコード(後に示します)で TGeocoder のインスタンスを作成し、データをセットアップすることができます。

TGeocoder.Current からは、ジオコーディング サービスを実際に実装しているクラスの型が返されます。"TGeocoder.Current.Create" のコードでは、指定された型のコンストラクタ(Create)を呼び出し、FGeocoder フィールドに保存しています。また、TGeocoder の逆ジオコーディングが完了したときに発生するイベント ハンドラを指定する必要もあります。OnGeocodeReverseEvent(前のステップで定義したもの)を FGeocoder.OnGeocodeReverse に代入します。

最後に、TGeocoder のインスタンスの作成が成功していて、かつ TGeocoder が動作中でなければ、位置情報を渡して TGeocoder.GeocodeReverse を呼び出します。TGeocoder がデータを受け取ると、OnGeocodeReverseEvent イベントが発生します。

Object Pascal の場合:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
  const OldLocation, NewLocation: TLocationCoord2D);
begin
  // code for previous steps goes here
try
    // Setup an instance of TGeocoder
    if not Assigned(FGeocoder) then
    begin
      if Assigned(TGeocoder.Current) then
        FGeocoder := TGeocoder.Current.Create;
      if Assigned(FGeocoder) then
        FGeocoder.OnGeocodeReverse := OnGeocodeReverseEvent;
    end;

    // Translate location to address
    if Assigned(FGeocoder) and not FGeocoder.Geocoding then
      FGeocoder.GeocodeReverse(NewLocation);
  except
    ListBoxGroupHeader1.Text := 'Geocoder service error';
  end;
end;

C++ の場合:

void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
                  const TLocationCoord2D &NewLocation)
{
        // code for previous steps goes here

                // Setup an instance of TGeocoder
        try {
        if (FGeocoder == NULL) {
            if (TGeocoder::Current != NULL) {
                FGeocoder = (TGeocoder*)new TGeocoderClass(TGeocoder::Current);
            }
            if (FGeocoder != NULL) {
                FGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;
            }
        }
        // Translate location to address

        if ((FGeocoder != NULL) && (FGeocoder->Geocoding)) {
            FGeocoder->GeocodeReverse(NewLocation);
        }
    }
    catch (...) {
        ListBoxGroupHeader1->Text = "Geocoder service error";
    }

}

リスト ボックス コンポーネントでの人が読み取れる住所の表示

先ほど述べたように、逆ジオコーディングが完了すると、OnGeocodeReverseEvent が発生します。

次に、住所パラメータ TCivicAddress に含まれるプロパティを代入して、人が読み取れる住所情報をリスト ボックス フィールドに表示します。

Object Pascal の場合:
procedure TForm1.OnGeocodeReverseEvent(const Address: TCivicAddress);
begin
  ListBoxItemAdminArea.ItemData.Detail       := Address.AdminArea;
  ListBoxItemCountryCode.ItemData.Detail     := Address.CountryCode;
  ListBoxItemCountryName.ItemData.Detail     := Address.CountryName;
  ListBoxItemFeatureName.ItemData.Detail     := Address.FeatureName;
  ListBoxItemLocality.ItemData.Detail        := Address.Locality;
  ListBoxItemPostalCode.ItemData.Detail      := Address.PostalCode;
  ListBoxItemSubAdminArea.ItemData.Detail    := Address.SubAdminArea;
  ListBoxItemSubLocality.ItemData.Detail     := Address.SubLocality;
  ListBoxItemSubThoroughfare.ItemData.Detail := Address.SubThoroughfare;
  ListBoxItemThoroughfare.ItemData.Detail    := Address.Thoroughfare;
end;

C++ の場合:

void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
{
          if (Address != NULL){
                ListBoxItemAdminArea->ItemData->Detail       = Address->AdminArea;
                ListBoxItemCountryCode->ItemData->Detail     = Address->CountryCode;
                ListBoxItemCountryName->ItemData->Detail     = Address->CountryName;
                ListBoxItemFeatureName->ItemData->Detail     = Address->FeatureName;
                ListBoxItemLocality->ItemData->Detail        = Address->Locality;
                ListBoxItemPostalCode->ItemData->Detail      = Address->PostalCode;
                ListBoxItemSubAdminArea->ItemData->Detail    = Address->SubAdminArea;
                ListBoxItemSubLocality->ItemData->Detail     = Address->SubLocality;
                ListBoxItemSubThoroughfare->ItemData->Detail = Address->SubThoroughfare;
                ListBoxItemThoroughfare->ItemData->Detail    = Address->Thoroughfare;
        }
}

アプリケーションでユーザー位置が必要な理由の記述

最終アプリケーションを配置する前に、[プロジェクト|オプション...|バージョン情報を選択し、NSLocationAlwaysUsageDescription および NSLocationWhenInUseUsageDescription の値に、アプリケーションでユーザーの位置を取得する理由を説明するメッセージを設定します。このメッセージは、iOS デバイスの位置を iOS がアプリケーションに提供できるよう、アプリケーションがユーザーに権限付与を依頼するときに、ユーザーに対して表示されます。

関連項目