타닥타닥 개발자의 일상

Kotlin 코틀린 안드로드 메인화면 Fragment에 구글 맵스 불러오고 주소 입력했을때 위도,경도로 변환하기 / 입력한 주소 메인화면 Fragment 구글맵스에 띄우기 본문

코딩 기록/Kotlin

Kotlin 코틀린 안드로드 메인화면 Fragment에 구글 맵스 불러오고 주소 입력했을때 위도,경도로 변환하기 / 입력한 주소 메인화면 Fragment 구글맵스에 띄우기

NomadHaven 2022. 2. 17. 22:42
편집이 필요한 문서

google_maps.api.xml

MainActivity

MapsFragment

activity_main.xml

fragment_maps.xml

AndroidMainifest.xml

build.gradle(:app)

 

*fragment_maps.xml은

com.example.googlemapsfragment 우클릭  > 새로 만들기 > Fragment > Google Maps Fragment 로 생성

 


google_maps.api.xml
<resources>
    <!--
    TODO: Before you run your application, you need a Google Maps API key.

    To get one, follow this link, follow the directions and press "Create" at the end:

    https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&r=03:9A:AB:2D:83:50:C0:32:AE:95:2C:AC:D3:82:72:47:B0:D9:15:CE%3Bcom.example.googlemapfragment

    You can also add your credentials to an existing key, using these values:

    Package name:
    com.example.googlemapfragment

    SHA-1 certificate fingerprint:
    03:9A:AB:2D:83:50:C0:32:AE:95:2C:AC:D3:82:72:47:B0:D9:15:CE

    Alternatively, follow the directions here:
    https://developers.google.com/maps/documentation/android/start#get-key

    Once you have your key (it starts with "AIza"), replace the "google_maps_key"
    string in this file.
    -->
    <string name="google_maps_key" translatable="false" templateMergeStrategy="preserve">YOUR API KEY</string>
</resources>

YOUR API KEY 부분에 구글맵스의 API 키를 넣는다.

API키 받는 법은 아래 링크의 글에 나와있다.

https://developerson.tistory.com/106

 

kotlin 코틀린 구글 맵스 API 안드로이드 화면에 불러와서 사용하는 법 , 시작 위치 지정하는 법

프로젝트 템플릿 선택시 Googles Maps Activity 선택 google_maps_api.xml 클릭 해당 문서에 있는 주소창을 ctrl+click하여 링크로 이동 https://developers.google.com/maps/documentation/android-sdk/start#..

developerson.tistory.com

 

 

AndroidManifest.xml

기존 AndroidManifest.xml의 문서에 아래 코드를 추가한다.

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

 

추가된 코드가 포함된 전체 코드

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.googlemapfragment">

    <!--
         The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
         Google Maps Android API v2, but you must specify either coarse or fine
         location permissions for the "MyLocation" functionality.
    -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.GoogleMapFragment">

        <!--
             The API key for Google Maps-based APIs is defined as a string resource.
             (See the file "res/values/google_maps_api.xml").
             Note that the API key is linked to the encryption key used to sign the APK.
             You need a different API key for each encryption key, including the release key that is used to
             sign the APK for publishing.
             You can define the keys for the debug and release targets in src/debug/ and src/release/.
        -->
        <meta-data
                android:name="com.google.android.geo.API_KEY"
                android:value="@string/google_maps_key"/>

        <activity
                android:name=".MainActivity"
                android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

 

build.gradle(:app)

기존의 build.gradle(:app) dependencies 부분의 아래의 코드를 추가한다.

   implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'com.google.android.gms:play-services-maps:17.0.0'

 

추가된 코드가 포함된 전체 코드

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.googlemapfragment"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'com.google.android.gms:play-services-maps:17.0.0'


    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

 

MapsFragment.kt
package com.example.googlemapfragment

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.location.Location
import androidx.fragment.app.Fragment

import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.gms.location.*

import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions

class MapsFragment(val activity: Activity) : Fragment(), OnMapReadyCallback {

    lateinit var locationPermission: ActivityResultLauncher<Array<String>>

    private lateinit var mMap: GoogleMap

    lateinit var fusedLocationClient: FusedLocationProviderClient
    lateinit var locationCallback: LocationCallback


    /*  private val callback = OnMapReadyCallback { googleMap ->
        val sydney = LatLng(-34.0, 151.0)
        googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
    }*/

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        locationPermission = registerForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()
        ) { results ->
            if (!results.all { it.value }) {
                Toast.makeText(activity, "권한 승인이 필요합니다.", Toast.LENGTH_LONG).show()
            }
        }

        //권한 요청
        locationPermission.launch(
            arrayOf(
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION
            )
        )



        return inflater.inflate(R.layout.fragment_maps, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
        mapFragment?.getMapAsync(this)
    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity)
     //   updateLocation() 현재 필요없다.
    }

    /*
    @SuppressLint("MissingPermission")
    fun updateLocation() {
        val locationRequest = LocationRequest.create()
        locationRequest.run {
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
            interval = 1000
        }

        locationCallback = object : LocationCallback() {
            //1초에 한번씩 변경된 위치 정보가 onLocationResult 으로 전달된다.
            override fun onLocationResult(locationResult: LocationResult?) {
                locationResult?.let {
                    for (location in it.locations) {
                        Log.d("위치정보", "위도: ${location.latitude} 경도: ${location.longitude}")
                        setLastLocation(location) //계속 실시간으로 위치를 받아오고 있기 때문에 맵을 확대해도 다시 줄어든다.

                    }
                }
            }
        }
        //권한 처리
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())

    }
    */

    fun setLocation(latitude:Double, longitude:Double) {
        val LATLNG = LatLng(latitude, longitude)

        val makerOptions = MarkerOptions()
            .position(LATLNG)
            .title("Here")

        val cameraPosition = CameraPosition.Builder()
            .target(LATLNG)
            .zoom(15.0f)
            .build()

        mMap.clear()
        mMap.addMarker(makerOptions)
        mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))


    }


}

 

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <FrameLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="633dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintVertical_bias="1.0">
    </FrameLayout>
    <Button
            android:text="Button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/mapBtn"
            app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.942" app:layout_constraintVertical_bias="0.158"/>
    <EditText
            android:layout_width="458dp"
            android:layout_height="42dp"
            android:inputType="textPersonName"
            android:ems="10"
            android:id="@+id/editTextadress"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintHorizontal_bias="0.676" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintVertical_bias="0.057"/>
    <EditText
            android:layout_width="159dp"
            android:layout_height="47dp"
            android:inputType="textPersonName"
            android:ems="10"
            android:id="@+id/editTextlong"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/editTextlat"
            app:layout_constraintHorizontal_bias="0.165" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.158"/>
    <TextView
            android:text="주소"
            android:layout_width="49dp"
            android:layout_height="25dp" android:id="@+id/textView"
            app:layout_constraintEnd_toStartOf="@+id/editTextadress"
            app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintHorizontal_bias="0.595" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintVertical_bias="0.075"/>
    <EditText
            android:layout_width="152dp"
            android:layout_height="45dp"
            android:inputType="textPersonName"
            android:ems="10"
            android:id="@+id/editTextlat"
            app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.214" app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.158"/>
</androidx.constraintlayout.widget.ConstraintLayout>

디자인 화면

 


MainActivity.kt
package com.example.googlemapfragment


import android.location.Address
import android.location.Geocoder
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.EditText
import java.io.IOException

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val fm = supportFragmentManager
        val fragmentTransaction = fm.beginTransaction()
        val mapsFragment = MapsFragment(this)
        fragmentTransaction.add(R.id.content, mapsFragment) // <- 수정됨
        fragmentTransaction.commit()

        val editTextadress = findViewById<EditText>(R.id.editTextadress)
        val editTextlat = findViewById<EditText>(R.id.editTextlat)
        val editTextlong = findViewById<EditText>(R.id.editTextlong)
        val mapBtn = findViewById<Button>(R.id.mapBtn)

        val geocoder: Geocoder = Geocoder(this)

        //위도 경도 초기화
        var latitude:Double = -34.0
        var longitude:Double = 151.0


        //주소를 위도 경도로 바꾸는 버튼
        mapBtn.setOnClickListener {
            var list:List<Address>? = null
            val address = editTextadress.text.toString()

            try {                                   //지역  , 읽을 개수
                list = geocoder.getFromLocationName(address, 10)
            } catch (e: IOException) {
                e.printStackTrace()
                Log.e("test", "입출력 오류 - 서버에서 주소변환시 에러발생")
            }
            if (list != null) {
                if(list!!.isEmpty()){
                    editTextlat.setText("None matched latitude")
                    editTextlong.setText("None matched longitude")
                    //혹은 아래의 코드로 대체가능
                // Toast.makeText(this, "해당되는 주소 정보는 없습니다", Toast.LENGTH_LONG).show()
                }else{
                    editTextlat.setText(list!![0].latitude.toString())
                    editTextlong.setText(list!![0].longitude.toString())

                    latitude = list!![0].latitude
                    longitude = list!![0].longitude

                    // 위도,경도 입력 후 지도
                    //MasFragment.kt에서 불러온 함수
                    mapsFragment.setLocation(latitude, longitude)


                }
            }
        }


    }
}

 


실행화면

실행 첫 화면
주소를 입력하면 위도와 경도가 출력된다

Comments