Android

[์กธ์—…์ž‘ํ’ˆ๊ธฐ] Kotlin์—์„œ ์‹ค์‹œ๊ฐ„ ์œ„์น˜ ๊ธฐ๋ฐ˜ ์ง€๋„ ์—ฐ๋™ํ•˜๊ธฐ

ej503 2023. 2. 27. 01:34

๐Ÿงจ ์กธ์—… ์ž‘ํ’ˆ ํŒ€ ํ”„๋กœ์ ํŠธ, Hear-Hero์˜ 2์›”

 

ํ•™๋ถ€ ์กธ์—…์ž‘ํ’ˆ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ์ ์–ด๋ณด๋ ค ํ•œ๋‹ค. ์กธ์—… ์ดํ›„ ํ•œ๋ฒˆ์— ์ ๊ธฐ์—๋Š” ๊ธฐ์–ต์ด ์ž˜ ๋‚˜์ง€ ์•Š๊ฑฐ๋‚˜, ์จ์•ผ ํ•  ๋ถ„๋Ÿ‰์ด ๋งŽ์„ ๊ฒƒ ๊ฐ™์•„ ์‹œ๊ฐ„์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ํšŒ๊ณ ๋ฅผ ์จ๋ณผ ์˜ˆ์ •์ด๋‹ค.

 

 

๐Ÿ™Œ ํ”„๋ก ํŠธ์—”๋“œ ์ฝ”๋“œ ๊ฐœ๋ฐœ

 

ํ”„๋ก ํŠธ์—”๋“œ์˜ ํŒŒ์ผ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ํฌ๊ฒŒ main, sounds, map, detail ๋กœ ๋‚˜๋‰œ๋‹ค. ์ด์— ํ•ด๋‹นํ•˜๋Š” ui ์ฝ”๋“œ์™€ event ๋“ฑ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ฃผ๋œ ์—…๋ฌด์˜€๋‹ค. 

 

 

๐Ÿ™Œ ๋”ฅ๋Ÿฌ๋‹ ์ฝ”๋“œ ๊ฐœ๋ฐœ

 

์†Œ๋ฆฌ ๋ฐ์ดํ„ฐ ์…‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํŠน์ • ์†Œ๋ฆฌ๋ฅผ ์ธ์‹ํ•˜๊ณ  ํŒ๋ณ„ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋ถ€๋ถ„์€ ์–ธ๋‹ˆ๊ฐ€ ๋งก์•„ ๋ชจ๋ธ์„ ๋น„๊ตํ•˜๋ฉฐ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜๋Š” ๋“ฑ ๋‹ค์–‘ํ•œ ์ผ์„ ํ•˜์…จ๋‹ค.

 

 

๐Ÿšง ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์–ด๋ ค์›€ : Place a real time location on Google Map

 

1. ๊ตฌ๊ธ€๋งต API ํ‚ค ์ถ”๊ฐ€ํ•˜๊ธฐ

 

API ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„๋กœ import ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„๊ณผ implementation ์—์„œ kotlin ๊ณผ java์˜ ๋ฐฉ๋ฒ•์ด ๋‹ฌ๋ผ ๊ตฌ๊ธ€๋ง์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค. ์ฝค๋งˆ์˜ ์œ„์น˜๋‚˜ ๊ด„ํ˜ธ ๋“ฑ ์‚ฌ์šฉ๋ฒ•์ด ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

 

2. ์†Œ์Šค ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

 

fun NavGraphBuilder.mealPlanScreen(
    navController: NavController,
    bottomBarPadding: PaddingValues,
    bottomBarState: MutableState<Boolean>
) {
    composable(
        route = Navigate.Screen.MealPlan.route
    ) {
        val sigapore = LatLng(1.35, 103.87)

        val cameraPositionState = rememberCameraPositionState {
            position = CameraPosition.fromLatLngZoom(sigapore, 10f)
        }
        var uiSettings by remember{ mutableStateOf(MapUiSettings()) }
        bottomBarState.value = true
       GoogleMap(
           modifier = Modifier
               .fillMaxWidth(fraction = 0.8f)
               .fillMaxHeight(0.5f),
           cameraPositionState = cameraPositionState,
           uiSettings = uiSettings
       ){
       }
    }
}

 

์ผ์ฐจ์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ GoogleMap import๋ฅผ ํ†ตํ•ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ถˆ๋Ÿฌ์™”๋‹ค.

import com.google.maps.android.compose.GoogleMap

์ƒ๋‹จ์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, LatLng์€ ๊ณ ์ •๋˜์–ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ด๋ฅผ ์‹ค์‹œ๊ฐ„ ์œ„์น˜๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

 

@SuppressLint("MissingPermission")
fun NavGraphBuilder.mealPlanScreen(
    navController: NavController,
    bottomBarPadding: PaddingValues,
    bottomBarState: MutableState<Boolean>,
) {
    composable(
        route = Navigate.Screen.MealPlan.route
    ) {

        val sigapore = LatLng(1.3139961,103.7041656)
        val cameraPositionState = rememberCameraPositionState {
            position = CameraPosition.fromLatLngZoom(sigapore, 10f)
        }
        val locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                for (location in locationResult.locations){
                    cameraPositionState.position = CameraPosition.fromLatLngZoom(LatLng(location.latitude, location.longitude), 10f)
                }
            }
        }
        val fusedLocationClient = LocationServices.getFusedLocationProviderClient(LocalContext.current)
        val locationRequest = LocationRequest.create().apply {
            interval = 10000
            fastestInterval = 5000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }
        fusedLocationClient.requestLocationUpdates(locationRequest,
            locationCallback,
            Looper.getMainLooper())

        val uiSettings by remember{ mutableStateOf(MapUiSettings()) }
        bottomBarState.value = true
        GoogleMap(
           modifier = Modifier
               .fillMaxWidth(fraction = 1.0f)
               .fillMaxHeight(0.7f),
           cameraPositionState = cameraPositionState,
           uiSettings = uiSettings
       ){}
        SoundMapButton()
    }
}

๋ฐ”๋กœ fusedLocationClient๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. FusedLocationProviderClient์—์„œ ๋งˆ์ง€๋ง‰์— ์ €์žฅ๋œ ์œ„์น˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ณ , locationCallback์œผ๋กœ ์ง€๋„ ์ƒ์˜ ์œ„์น˜๋ฅผ ๊ณ„์†ํ•ด ์—…๋ฐ์ดํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

๐Ÿ‘ 2์›” ํšŒ๊ณ 

 

์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์˜ ๋„์›€์„ ๋งŽ์ด ๋ฐ›์•˜๋‹ค. ํŠนํžˆ ์‹ค์‹œ๊ฐ„ ์œ„์น˜ ์—ฐ๋™์˜ ๊ฒฝ์šฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งŽ์•„์„œ ์‚ฌ์šฉ ์ค‘์ด๋˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋‹ค๋ฅธ ๊ฒƒ์˜ ์†Œ์Šค๋ฅผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์‚ผ์•˜์„ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋งŽ์ด ๋‚ฌ์—ˆ๋‹ค. ์ค‘๊ฐ„์—๋Š” LatLng์ด ๋ฐ›์•„์ง€์ง€ ์•Š์•„ ์œ ๋Ÿฝ ๋ฐ”๋‹ค ํ•œ ๊ฐ€์šด๋ฐ (0, 0)์— ์žˆ๊ธฐ๋„ ํ–ˆ๋‹ค ^^;; ๊ทธ๋ฆฌ๊ณ  UI ์„ค๊ณ„๋ฅผ ํ•  ๋•Œ relatative ํ•œ ๊ด€๊ณ„๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ™”๋ฉด์˜ ํฌ๊ธฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ๋ชจ์Šต์ด ์ด์ƒํ•ด์ง€์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋А๊ผˆ๋‹ค. ์•Œ์•„์„œ ์ฒ™์ฒ™ ์ž˜ ๋ฐ”๋€Œ์–ด์ฃผ๋ฉด ์ข‹์œผ๋ จ๋งŒ... ใ…Žใ…Ž ๊ทธ๋Ÿผ ๋‹ค์Œ ๋‹ฌ๋„ ์•„์ž ์•„์ž!