[Flutter] 근태관리 앱 : Google Maps 지도/ 지도마커/ 지도 동그라미/ 현재 위치 표시 및 위도,경도 구하기/ 위도,경도간 거리 구하기

jini.choi·2024년 4월 11일
0

flutter

목록 보기
9/9

세팅

https://pub.dev/ 에서 필요한 패키지 다운

  • google_maps_flutter(구글맵 사용할 때 필요), geolocator(위치 관련 작업에 필요)

google_maps_flutter

Google Maps 지도 사용하기

  • LatLng 클래스에 위도 경도 넘겨줌
 static const LatLng companyLatLag = LatLng(
    37.49793912003677,
    127.02758462751584,
  );
  • 줌 레벨 설정
static const CameraPosition initialPosition = CameraPosition(
    target: companyLatLag,
    zoom: 15,  //숫자가 낮을 수록 멀리서 보임
  );
  • GoogleMap 위젯 사용
 Widget build(BuildContext context) {
    return const Scaffold(
      body: GoogleMap(
        mapType: MapType.terrain, //맵 종류 선택
        initialCameraPosition: initialPosition,
      ),
    );
  }

앱 권한관리(위치 권한 받기)

  • 권한 관련 모든 기능은 async로 관리(왜냐하면 권한 요청을 하고서 유저의 인풋을 기다려야되기 때문에)
Future<String> checkPermission() async {
    // 로케이션 서비스가 활성화가 돼있는지 확인
    final isLocationEnbled = await Geolocator.isLocationServiceEnabled();

    if (!isLocationEnbled) {
      return '위치 서비스를 활성화 해주세요.';
    }

    //현재 앱이 갖고 있는 위치서비스에 대한 권한이 어떻게 되는지 가져옴
    LocationPermission checkedPermision = await Geolocator.checkPermission();

    if (checkedPermision == LocationPermission.denied) {
      //denied면 초기상태로 한번은 request해주지만
      checkedPermision = await Geolocator.requestPermission();
	
      //그래도 denied면 텍스트 띄움
      if (checkedPermision == LocationPermission.denied) {
        return '위치권한을 허용해주세요.';
      }
    }

    if (checkedPermision == LocationPermission.deniedForever) {
      return '앱의 위치 권한을 세팅에서 허가해주세요.';
    }

    return '위치권한이 허용되었습니다.';
  }

UI(FutureBuilder 위젯 사용)

FutureBuilder(future: future, builder: builder)

  • future를 리턴해주는 어떤 함수든 넣을수 있음 (Future<String> chec~)

  • future의 함수의 상태가 변경이 될 때마다 함수의 상태가 로딩중이거나 로딩이끝났거나 어떤 데이터가 리턴됐거나 에러가 터졌거나 등 상황이 됐을 때 builder:(){}를 다시 실행해가지고 화면을 다시 그려줄 수 있다.

  • future안에 들어간 함수가 리턴해준 값을 snapshot에서 또 받아볼 수 있다.

    • print(snapshot.data); - 함수의 return값
    • print(snapshot.connectionState);- 함수 현재 상태확인
return Scaffold(
      appBar: renderAppBar(),
      body: FutureBuilder(
        future: checkPermission(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          }

          // data가 '위치권한이 허용되었습니다.'면 지도 리턴해줌
          if (snapshot.data == '위치권한이 허용되었습니다.') {
            return const Column(
              children: [
                _CustomGoogleMap(initialPosition: initialPosition),
                _ChoolCheckButton(),
              ],
            );
          }

          return Center(
            child: Text(snapshot.data),
          );
        },
      ),
    );

지도에 원 그리기

  • 시뮬레이터(안드로이드) 옆에 ... 누르고 Location에서 폰 위치 설정해줌 (안하면 구글 본사 잡히는것 같다.)

  • GoogleMap위젯에 myLocationEnabled: true, 속성 추가해주면 현재위치를 표시해주는 원이 그려진다.

child: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: initialPosition,
        myLocationEnabled: true,
      ),

반경 100m에 원그리기

  • 반경 100m 이내에서만 출석할수 있게하기

  • companyLatLag를 위치로 기준으로 함

  • Circle 만들어줌

static const double distance = 100;

  static Circle circle = Circle(
    circleId: const CircleId('circle'), //여러 동그라미 그렸을때 구분하기 위함
    center: companyLatLag, //companyLatLag를 위치로 기준
    fillColor: Colors.blue.withOpacity(0.5),
    radius: distance, //반지름 - 출석체크를 해줄수있는 거리
    strokeColor: Colors.blue,
    strokeWidth: 1,
  );
  • _CustomGoogleMap에서 final Circle circle; 받아와서 GoogleMap위젯에 circles: {circle}, 를 추가해준다.(Set이라 {}로 감싸줘야함)

마커 표시하기

  • companyLatLag를 위치로 기준으로 함

  • Circle 만들어줌

static Marker marker = const Marker(
    markerId: MarkerId('marker'),
    position: companyLatLag,
  );
  • _CustomGoogleMap에서 final Marker marker; 받아와서 GoogleMap위젯에 markers: {marker}, 를 추가해준다.

현재 위치 반경안 존재여부에 따른 원변경(StreamBuilder 위젯 사용하기)

  • 반경 밖에 있을때 빨강/ 반경 안에 있을 떄 파랑/ 출석체크 했을 때 초록

  • circle를 세개 만들어서 StreamBuilder<Position> 내 위치를 Position 클래스로 보내준다.

  • Geolocator.getPositionStream()메서드는 현재 위치가 변경이될 때마다 값이 Stream에서 리턴(빌드)이 되게 해준다.

  • start은 내 현재위치/ end는 회사로 위치로 할당해주고

  • start와 end의 거리를 실시간으로 구해야되기 때문에 Geolocator.distanceBetween() 메서드를 사용한다.

  • distance는 거리를 구하고, okDistance는 100m라고 설정이 되어있다.
    그래서 if (distance < okDistance){isWithinRange = true;} 를 통해 현재 start와 end의 거리가 100m보다 작으면 isWithinRange를 true로 할당해준다.

  • isWithinRange를 활용해서 _CustomGoogleMap 에 조건문으로 circle를 넘겨주고
    _ChoolCheckButton도 isWithinRange활용해서 조건문으로 버튼색 바꿔주고
    [출근하기] 버튼도 조건문으로 보여준다.

if (snapshot.data == '위치권한이 허용되었습니다.') {
            return StreamBuilder<Position>(
              stream: Geolocator
                  .getPositionStream(), //현재 위치가 변경이될 때마다 값이 스트림에서 리턴(빌드)이 됨다.
              builder: (context, snapshot) {
                // print(snapshot.data); //현재위치에따라 실시간으로 빌드되는지 위경도찍어봄
                bool isWithinRange = false;

                if (snapshot.hasData) {
                  final start = snapshot
                      .data!; //내 위치를<Position>이라는 클래스로 표현한게 snapshot.data
                  const end = companyLatLag;

                  // 거리를 구하는 함수
                  final distance = Geolocator.distanceBetween(
                    start.latitude,
                    start.longitude,
                    end.latitude,
                    end.longitude,
                  );

                  if (distance < okDistance) {
                    isWithinRange = true;
                  }
                }

                return Column(
                  children: [
                    _CustomGoogleMap(
                      initialPosition: initialPosition,
                      circle: isWithinRange
                          ? whitDistanceCircle
                          : notWhitDistanceCircle,
                      marker: marker,
                    ),
                    _ChoolCheckButton(
                        isWithinRange: isWithinRange,
                        onPressed: onCoolCheckPressed),
                  ],
                );
              },
            );
          }

materialDialog

  • materialDialog 패키지에서 showDialog(context: context, builder: builder) 가져옴

  • AlertDialog 위젯을 사용해서 위젯을 띄어줌

  • actions로 선택할 수 있는 버튼을 추가할 수 있다.

profile
개발짜🏃‍♀️

1개의 댓글

comment-user-thumbnail
2025년 2월 25일

안녕하세요 구글 지도 패키지에 저런 원형 마커가 없던데 어떻게 설정하신건가요? 궁금합니다...

답글 달기