[피플]플러터 Google Map Api 사용 방법

2023. 2. 20. 23:59·Flutter
728x90

안녕하세요 불망입니다!

피플에서 메인 기능으로 지도 커뮤니티를 기획하게 되어서 지도 개발을 시작 하였습니다.

간단한 아키텍처 구성을 해봤습니다.

- 모든 헌혈의 집 위치를 가져와서 마커 표시
- 마커 눌렀을 때
- 바텀 시트 조금 보여주기
- 바텀 시트 눌렀을 때
- 센터 상세페이지로 이동
- 지도 탭을 눌렀을 때 현재 위치 가져와서 보여주기
- 검색창은 기존 검색창 사용
- 검색 했을 때 검색 결과를 누르면 좌표이동해서 보여주기
- 검색 결과 필터링(지도 완성후 기능추가 & 백엔드)
- 헌혈의 집 버튼 : 헌혈의 집만 마커 표시
- 헌혈의 카페 버튼 : 헌혈의 카페만 마커 표시
- 가까운 헌혈의 집 보여주기(지도 완성 후 기능 추가)
- 내 위치표시 : 내 현재 위치 표시
- 아이콘 커스텀마이징
위 기능들을 하나씩 개발을 하려고 합니다. 

지도 환경 설정

google_maps_flutter 패키지를 프로젝트에 추가합니다. 이 패키지는 Google Maps를 플러터에서 사용할 수 있도록 지원합니다

dependencies:
  google_maps_flutter: ^2.1.0
	geolocator: ^8.0.3 // 유저 위치 가져오기

Android : android/app/src/main/AndroidManifest.xml에 밑에 코드 추가

<manifest ...
  <application ...
    <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR KEY HERE"/>

iOS : ios/Runner/AppDelegate.swift에 코드 추가

import UIKit
import Flutter
import GoogleMaps

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey("YOUR KEY HERE")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

유저 현재 위치 가져오기(설정)

Android : android/app/src/main/AndroidManifest.xml에 밑에 코드 추가

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

iOS : Runner/Info.plist에 추가

<key>NSLocationWhenInUseUsageDescription</key>
<string>유저 위치를 가져와도 될까요?</string>

메엔 함수에다 사용자의 위치 정보 호출 (예시)

밑 코드에서는 checkPermission() 함수를 사용하여 위치 권한 상태를 확인하고, 권한이 거부된 경우 requestPermission() 함수를 사용하여 사용자에게 권한을 요청합니다.

위 코드에서 사용되는 WidgetsFlutterBinding.ensureInitialized() 함수는 runApp() 함수를 호출하기 전에 **WidgetsBinding**을 초기화하는 데 사용됩니다. 이 함수를 호출하지 않으면 **ServicesBinding**을 사용하는 일부 패키지에서 문제가 발생할 수 있습니다.

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final status = await Geolocator.checkPermission();
  if (status == LocationPermission.denied) {
    await Geolocator.requestPermission();
  }
  runApp(MyApp());
}

앱 설명

  • 플러터를 사용하여 안드로이도, 아이폰 둘 다 지도를 가져오고 간단한 지도 기능을 사용합니다.

앱 기능

  • 유저 현재 위치 가져오는 버튼
  • 좌표값을 가져와서 마커 찍기
  • 마커를 누르면 바텀시트 나오게 하기
  • 바텀시트 누르면 디테일페이지로 이동

다른 코드 내용

개인적인 코드이며 유저 위치 마커 기본적인 코드 내용입니다.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final status = await Geolocator.checkPermission();
  if (status == LocationPermission.denied) {
    await Geolocator.requestPermission();
  }
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: map_widget(),
    );
  }
}

class map_widget extends StatefulWidget {
  const map_widget({Key? key,required}) : super(key: key);

  @override
  State<map_widget> createState() => _map_widgetState();
}

class _map_widgetState extends State<map_widget> {
  late GoogleMapController _controller;
  bool _myLocationEnabled = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> _getCurrentLocation() async {
    final position = await Geolocator.getCurrentPosition();
    final cameraPosition = CameraPosition(
      target: LatLng(position.latitude, position.longitude),
      zoom: 18,
    );
    _controller.animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
    setState(() {
      _myLocationEnabled = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    List<Map<String, dynamic>> places = [  {    'name': 'Place 1',    'latitude': 37.532600,    'longitude': 127.024612,  },  {    'name': 'Place 2',    'latitude': 37.532700,    'longitude': 127.024712,  },  {    'name': 'Place 3',    'latitude': 37.532800,    'longitude': 127.024812,  },  {    'name': 'Place 4',    'latitude': 37.532900,    'longitude': 127.024912,  },  {    'name': 'Place 5',    'latitude': 37.533000,    'longitude': 127.025012,  },  {    'name': 'Place 6',    'latitude': 37.533100,    'longitude': 127.025112,  },];
    return CupertinoPageScaffold(
      child: Stack(
        children: [
          GoogleMap(
            initialCameraPosition: CameraPosition(
              target: LatLng(37.532600, 127.024612), // 서울 시청 위치
              zoom: 18,
            ),
            myLocationEnabled: _myLocationEnabled,
            myLocationButtonEnabled: false,
            markers: Set<Marker>.of(places.map((place) {
              return Marker(
                markerId: MarkerId(place['name']),
                position: LatLng(place['latitude'], place['longitude']),
                infoWindow: InfoWindow(title: place['name']),
                onTap: () {
                  Navigator.push(
                      context,
                      CupertinoPageRoute(builder: (context) => MarkerDetailScreen())
                  );
                },
              );
            })),
            onMapCreated: (controller) => _controller = controller,
          ),
          Positioned(
            bottom: 16,
            right: 16,
            child: FloatingActionButton(
              onPressed: _getCurrentLocation,
              foregroundColor: Colors.black,
              backgroundColor: Colors.white,
              elevation: 8, // 그림자 크기
              child: Icon(Icons.my_location),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(10), // 버튼 모서리 둥글기
              ),
            ),
          ),
          Positioned(
            top: 54,

            child: CupertinoButton(
              onPressed: () {
                Navigator.push(
                    context,
                    CupertinoPageRoute(builder: (context) => MarkerDetailScreen())
                );
              },
              child: Container(
                width: MediaQuery.of(context).size.width - 21,
                height: 44,

                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(left: 16.0),
                      child: Text('위치 검색',
                        style: const TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.w600,
                          color: Colors.grey,

                        ),
                      ),
                    ),
                    const Spacer(),
                    Padding(
                      padding: const EdgeInsets.only(right: 13.0),
                    ),
                  ],
                ),
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.all(Radius.circular(8))
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class MarkerDetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Marker Detail'),
      ),
      body: Center(
        child: Text('Marker detail screen'),
      ),
    );
  }
}

class marker_widget extends StatelessWidget {
  const marker_widget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}
728x90

'Flutter' 카테고리의 다른 글

[Flutter] WhiteScreen 해결(iPhone 무선빌드) & Load Sequence Flutter UI  (3) 2024.11.21
[피플] 디자인 QA  (0) 2023.02.24
[피플] 응원해요 기능 수정  (0) 2023.02.08
[피플] - 이슈 수정 (git, 협업능력)  (0) 2023.02.03
[Flutter 문법]StatefulWidget parameter 넘겨주기  (0) 2023.01.20
'Flutter' 카테고리의 다른 글
  • [Flutter] WhiteScreen 해결(iPhone 무선빌드) & Load Sequence Flutter UI
  • [피플] 디자인 QA
  • [피플] 응원해요 기능 수정
  • [피플] - 이슈 수정 (git, 협업능력)
bulmang
bulmang
모바일 개발자 도전
  • bulmang
    bulmang
    bulmang
  • 전체
    오늘
    어제
    • 분류 전체보기 (208)
      • 알고리즘 (68)
        • List (3)
        • Two Pointer (6)
        • Binary Search (4)
        • Prefix Sum (3)
        • Sort (4)
        • Brute Force (5)
        • Array (2)
        • String (4)
        • 프로그래머스 (12)
        • 백준 (9)
        • Queue (2)
        • Stack (2)
        • Recursion (12)
      • Computer Science (16)
        • Computer Architecture (6)
        • Operating System (5)
        • Network (2)
        • 기타 (2)
        • System Programming (1)
      • Swift (70)
        • 개발 (24)
        • 정리 (25)
        • 문법 (20)
      • Flutter (24)
      • 기타 (12)
        • 후기 (12)
      • Git (6)
      • Ios 오픈소스 (5)
      • UI 디자인 (5)
      • AppleScript (2)
  • 링크

    • Notion
    • Github
  • 태그

    Xcode
    코딩테스트
    자료구조
    today i learned
    Java
    백준
    알고리즘
    Swift
    riverpod
    문법
    피플
    FLUTTER
    개발
    IOS
    til
    SwiftUI
    협업
    Apple Developer Academy
    재귀
    컴퓨터구조
  • 최근 댓글

  • 최근 글

  • 인기 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.2
bulmang
[피플]플러터 Google Map Api 사용 방법
상단으로

티스토리툴바