๊ฐœ๋ฐœ ์ผ์ง€ ๐Ÿ’ป/Swemo

Nutri Capture - ContentWithSwipeableBottomSheet() ๋„์ž…

interfacer_han 2025. 10. 31. 15:04

#1 ๊ฐœ์š”

๊ฐœ๋ฐœํ•ด ๋‘” ์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณธ ํ”„๋กœ์ ํŠธ(Nutri Capture)์—์„œ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

#2 ๊ฐœ์„ ํ•œ ํฌ์ธํŠธ

 

ContentWithSwipeableBottomSheet()

#1 ๊ฐœ์š”BottomSheetScaffold()์˜ ๋ฌธ์ œ์ ์„ ๊ฐœ์„ ํ•œ, ์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ ContentWithSwipeableBottomSheet()๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค (๊ฒŒ์‹œ๊ธ€ ๋งจ ์•„๋ž˜์— ์†Œ์Šค์ฝ”๋“œ ์žˆ์Œ). #2 BottomSheetScaffold()#2-1 ๊ฐœ์š” androidx.compose.material | API reference

kenel.tistory.com

์œ„์˜ ์ปค์Šคํ…€ Scaffold๋ฅผ Nutri Capture ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ–ˆ๋‹ค.

 

#3 ์ฝ”๋“œ ์Šค๋‹ˆํŽซ

#3-1 class MainActivity

...

...
class MainActivity : ComponentActivity() {

    ...

    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...

        ...
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
        setContent {
            ...
        }
    }
}

BottomSheet์˜ ๋งค๋„๋Ÿฌ์šด ๋™์ž‘์„ ์œ„ํ•ด, ContentWithSwipeableBottomSheet()๋Š” window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) ์—†์ด ๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•ด ๋‘์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์„ ์–ธํ•ด ๋‘”๋‹ค.

 

#3-2 fun NutrientScreen()

...

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NutrientScreen() {
    val sheetState = rememberContentWithSwipeableBottomSheetState(
        anchoredDraggableState = AnchoredDraggableState(SheetValue.PartiallyExpanded)
    )

    var sheetExpandedAnchorOffset by remember { mutableStateOf(0.dp) }
    val statusBarHeightDp = with(LocalDensity.current) {
        WindowInsets.statusBars.getTop(this).toDp()
    }
    LaunchedEffect(statusBarHeightDp) {
        sheetExpandedAnchorOffset = statusBarHeightDp
    }

    ContentWithSwipeableBottomSheet(
        sheetContent = {
            NutrientBottomSheet()
        },
        modifier = Modifier
            .fillMaxSize()
            .background(BottomAppBarDefaults.containerColor),
        sheetState = sheetState,
        sheetExpandedAnchorOffset = sheetExpandedAnchorOffset,
        sheetPartiallyExpandedHeight = storedImeMaxHeight(),
        sheetSwipeEnabled = true,
        hasContentNavigationBarPadding = true
    ) {
        Column(modifier = Modifier.fillMaxSize()) {
            NutrientHistory()
            NutrientChatBar()
        }
    }
}

์ด ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ–ˆ๋‹ค.

 

#3-3 object SystemPreferences

// package com.example.datastore

import android.content.Context
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlin.math.roundToInt

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "system")

object SystemPreferences {
    val IME_MAX_HEIGHT_VALUE_KEY = intPreferencesKey("ime_max_height_dp")
    val DEFAULT_IME_MAX_HEIGHT_VALUE = 250.dp.value.roundToInt()

    private lateinit var appContext: Context

    fun init(context: Context) {
        appContext = context
    }

    fun getImeMaxHeight(): Flow<Dp> {
        return appContext.dataStore.data.map { preferences ->
            (preferences[IME_MAX_HEIGHT_VALUE_KEY] ?: DEFAULT_IME_MAX_HEIGHT_VALUE).dp
        }
    }

    suspend fun setImeMaxHeight(imeHeight: Dp) {
        appContext.dataStore.edit { preferences ->
            preferences[IME_MAX_HEIGHT_VALUE_KEY] = imeHeight.value.toInt()
        }
    }
}

Bottom Sheet๊ฐ€ ๋๊นŒ์ง€ ์˜ฌ๋ผ์˜จ ๋†’์ด๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ฝ๋Š” ํด๋ž˜์Šค๋‹ค. ":datastore"๋ผ๋Š” ๋ชจ๋“ˆ์„ ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ  ๊ทธ ์•ˆ์— ์ด ํด๋ž˜์Šค๋ฅผ ๋„ฃ์—ˆ๋‹ค.

 

#3-4 class Application (@HiltAndroidApp)

// package com.example.nutri_capture_new

import android.app.Application
import com.example.datastore.SystemPreferences
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class NcApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        SystemPreferences.init(context = this)
    }
}

SystemPreferences๊ฐ€ UI ๋‹จ์— null ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๊ฑธ ๋ง‰๊ธฐ ์œ„ํ•ด, Application ํด๋ž˜์Šค์—์„œ ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ํ•ด์ค€๋‹ค.

 

#4 ์†Œ์Šค ์ฝ”๋“œ

#4-1 ์ด ๊ฒŒ์‹œ๊ธ€ ์‹œ์ ์˜ Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com

 

#4-2 ๋ณธ ํ”„๋กœ์ ํŠธ์˜ ๊ฐ€์žฅ ์ตœ์‹  Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com