【Flutter】GoogleMapを使用したアプリの開発について Part2

flutter

端末位置の取得について

前回は地図の表示のみを行いました。

実際のアプリでは端末の現在地を表示する機能を持っています。

現在地表示を行うための設定についてまとめたいと思います。

また、GoogleMap自体は色々な機能を持っているので、合わせて使ってみようと思います。

端末の位置情報を取得するためには、別のライブラリを使用します。

pubspec.yaml の dependencies に追加します。

  geolocator: ^8.2.0

許可設定について

ライブラリの他に、端末の位置を取得する際は権限の設定が必要になります。

Android

android/app/src/main/AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

iOS

ios/Runner/Info.plist

<key>NSLocationWhenInUseUsageDescription</key>
<string>Required to post location information when posting photos and videos.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Required to post location information when posting photos and videos.</string>

許可設定を行っていますが、実際にはユーザに許可を得る必要があります。

このユーザの許可は、関連機能を実行する前であればどこで行っても良いのですが、アプリの開始時点に設定をすることもできます。

メイン関数の呼び出し方法を変更します。

void main() => runApp(const MyApp());

この部分を以下に変更します。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  Future(() async {
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      await Geolocator.requestPermission();
    }
  });
  runApp(const MyApp());
}

この記述にしておくと、アプリを呼び出した時点で承認してもらうフローになります。

アプリのメイン機能として端末の位置情報を扱う場合は、最初にユーザーに許可を宣言してもらう方が効率が良いからです。

一旦これで起動してみましょう。

確認画面が出ました。(画面はiOSです)

さらにメインの_MyAppStateクラスを修正します。

class _MyAppState extends State<MyApp> {
  bool _hasPosition = false;
  late GoogleMapController mapController;

  // 初期値は東京駅
  LatLng _center = const LatLng(35.6814999, 139.7654987);

  final Set<Marker> _markers = {
    const Marker(
        markerId: MarkerId("1"),
        position: LatLng(35.6814999, 139.7654987),
        infoWindow: InfoWindow(title: "東京駅")),
    Marker(
        markerId: const MarkerId("2"),
        position: const LatLng(35.4683206, 139.6228339),
        infoWindow: const InfoWindow(title: "横浜駅"),
        icon: BitmapDescriptor.defaultMarkerWithHue(30)),
    Marker(
        markerId: const MarkerId("3"),
        position: const LatLng(35.8802697, 139.6121077),
        infoWindow: const InfoWindow(title: "浦和駅"),
        icon: BitmapDescriptor.defaultMarkerWithHue(210)),
  };

  // 現在地を取得しGoogleMapを表示する。
  Future<void> _getLocation() async {
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    _center = LatLng(position.latitude, position.longitude);
    setState(() {
      _hasPosition = true;
    });
  }

  // 東京駅を中心とした俯瞰画面に切り替える
  Future<void> _changeView() async {
    await mapController
        .animateCamera(CameraUpdate.newCameraPosition(const CameraPosition(
      target: LatLng(35.6814999, 139.7654987),
      zoom: 17,
      bearing: 90.0,
      tilt: 60.0,
    )));
  }

  void _onMapCreated(GoogleMapController controller) {
    mapController = controller;
  }

  Widget _createMap(LatLng center) {
    return Expanded(
      child: GoogleMap(
        mapType: MapType.hybrid,
        onMapCreated: _onMapCreated,
        // 端末の位置情報を使用する。
        myLocationEnabled: true,
        // 端末の位置情報を地図の中心に表示するボタンを表示する。
        myLocationButtonEnabled: true,
        initialCameraPosition: CameraPosition(target: center, zoom: 10),
        // マーカを表示する。
        markers: _markers,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Maps Sample App'),
          backgroundColor: Colors.green[700],
        ),
        body: Column(
          children: [
            !_hasPosition
                ? ElevatedButton(
                    onPressed: () {
                      _getLocation();
                    },
                    child: const Text("View Map"))
                : ElevatedButton(
                    onPressed: () {
                      _changeView();
                    },
                    child: const Text("Change View")),
            _hasPosition ? _createMap(_center) : Container(),
          ],
        ),
      ),
    );
  }
}

シミュレータでの現在地設定について

geolocatorで、実際に端末の情報を取得する際には以下の記述をしています

Position position = await Geolocator.getCurrentPosition(
    desiredAccuracy: LocationAccuracy.high);

ラップしているメソッドは非同期であるaysncを入れています。 名前付き引数で設定している内容は、位置情報の精度を指定しています。

この時シミュレータで実行している場合、位置情報は以下で設定します。一旦、どちらも渋谷駅にしています。(北緯35.6580339:東経139.6994471)

AndroidStudioシミュレータの場合は以下の部分から設定できます。

iOSシミュレータは以下から設定が可能です。

GoogleMap表示設定について

GoogleMapの設定はこの部分です。

  Widget _createMap(LatLng center) {
    return Expanded(
      child: GoogleMap(
        mapType: MapType.hybrid,
        onMapCreated: _onMapCreated,
        // 端末の位置情報を使用する。
        myLocationEnabled: true,
        // 端末の位置情報を地図の中心に表示するボタンを表示する。
        myLocationButtonEnabled: true,
        initialCameraPosition: CameraPosition(target: center, zoom: 10),
        // マーカを表示する。
        markers: _markers,
      ),
    );
  }

実行すると、ボタンが表示されます。このボタンをタップすると、地図が表示されます。

他に、前回に比べて設定を変えています。

  • 地図を衛星画像表示にする。
  • 設定したマーカを表示する。
  • 端末位置を中心に表示するボタンを表示する。

マーカはタップすると、吹き出しに説明が出ます。

一度タップしたボタンは再度タップすると視点を変更する機能をつけています。東京駅を中心に東方向を俯瞰しています。

色々できるGoogleMapですので、自身で動かしてみるのも面白いと思います。

今回は以上です。ありがとうございました。

関連記事

  1. flutter

    【Flutter】CustomPainterを使い、図形を描画

  2. flutter

    【Flutter】アプリ名やアイコンの変更とローンチスクリーンの表示

  3. flutter

    【Flutter】GraphQLClientを使ってGraphQL・A…

  4. flutter

    【Flutter】table_calendarを使用してカレンダーを表…

  5. flutter

    Flutterのすゝめ

  6. 【Widget of the Week】#6 FutureBuilde…

最近の記事

  1. AWS
  2. AWS
  3. AWS
  4. AWS
  5. AWS

制作実績一覧

  1. Checkeys