Compose 감잡기

2022. 2. 24. 15:12Android/AAC

- Material component composable : Compose built-in으로 기본 제공하는 composable -> 결국 우리가 만드는 custom composable은 이것을 이용하는 것

https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary?hl=ko#components 

 

androidx.compose.material  |  Android Developers

androidx.car.app.managers

developer.android.com

 

- 필수로 알아두면 좋은 Material component composable

1. MaterialTheme : App의 Theme을 설정할 수 있음

@Composable
fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
) { ... }
// Example
@Composable
fun HanwhalifeTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }

    MaterialTheme(
        colors = colors,
        typography = Typography,
        shapes = Shapes,
        content = content
    )
}

 

2. Scaffold : Material component composable을 일반 화면 패턴으로 결합하는 레이아웃 composable, param으로 받는 content composable의 input인 PaddingValues는 topBar, bottomBar에 의해 결정되는 content 표시 영역의 오프셋임.

@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable () -> Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit
) { ... }
// Example
@Composable
fun HanwhalifeHome() {
    val context = LocalContext.current
    val navController = rememberNavController()
    val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    }
    Scaffold(
        topBar = {
            HanwhalifeTopBar(navController = navController)
        },
        bottomBar = {
            val items = listOf(
                Screen.MyContract,
                Screen.FindProduct,
                Screen.FullMenu
            )
            HanwhalifeBottomNavigation(navController = navController, items = items)
        }
    ) { innerPadding ->
        HanwhalifeNavHost(
            navController = navController,
            viewModelStoreOwner = viewModelStoreOwner,
            modifier = Modifier.padding(innerPadding)
        )
    }
}

 

3. BottomNavigation : 하단 Navigation 구성할 수 있음

@Composable
fun BottomNavigation(
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: Dp = BottomNavigationDefaults.Elevation,
    content: @Composable RowScope.() -> Unit
) { ... }
// Example
@Composable
fun HanwhalifeBottomNavigation(navController: NavHostController, items: List<Screen>) {
    BottomNavigation(backgroundColor = MaterialTheme.colors.surface) {
        val navBackStackEntry by navController.currentBackStackEntryAsState()
        val currentDestination = navBackStackEntry?.destination
        items.forEach { screen ->
            BottomNavigationItem(
                icon = {
                    Icon(
                        painter = painterResource(id = screen.drawableResId),
                        contentDescription = stringResource(screen.stringResId)
                    )
                },
                label = { Text(stringResource(screen.stringResId)) },
                selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                onClick = {
                    navController.navigate(screen.route) {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
                }
            )
        }
    }
}

 

4. NavHostController : Navigation 구성 시 item에 대한 컨트롤 제공(ex>page 변경), param으로 넘겨지는 navigators는 특정 정책을 가진 navigator를 추가해 NavHostController내 navigatorProvider에 추가되는 값이다.(언제 왜 쓰는지는 예제를 봐야알 것 같음)

* NavController 는 컴포즈에서 네비게이션을 쓸때 사용되는 메인 컴포넌트이다. 이는 스택을 관리하는 역할을 하며, screen state 사이를 네비게이팅할때 각 스텍을 tracking한다. NavController 는 탐색하는데 있어서 center이며, destinations에 도달하기 위해 가장 먼저 만들어져야한다.

NavController의 서브클래스인 NavHostController로 작업한다. rememberNavController()를 사용하여 NavController를 얻는다. 이것이 NavController 를 만들고 remember하며, configuration이 바뀔 지라도 살아남게 된다. 

NavController는 single NavHost composable와 연관되어있다. NavHost 는 NavController와 Navigation Graph(Jetpack Navigation 사용 시)를 연결시켜서 composable의 destination을 특정시킨다.

@Composable
public fun rememberNavController(
    vararg navigators: Navigator<out NavDestination>
): NavHostController { ... }
// Example
@Composable
fun HanwhalifeHome() {
    val context = LocalContext.current
    val navController = rememberNavController()
    ...
}

 

5. LazyColumn : 화면에 보여지는 composable만 표시하는 scrollable한 column composable(로딩 시간 최적화 가능)

@Composable
fun LazyColumn(
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    userScrollEnabled: Boolean = true,
    content: LazyListScope.() -> Unit
) {
    LazyList(
        modifier = modifier,
        state = state,
        contentPadding = contentPadding,
        flingBehavior = flingBehavior,
        horizontalAlignment = horizontalAlignment,
        verticalArrangement = verticalArrangement,
        isVertical = true,
        reverseLayout = reverseLayout,
        userScrollEnabled = userScrollEnabled,
        content = content
    )
}
// Example
LazyColumn(
    modifier = Modifier
        .wrapContentHeight()
        .fillMaxWidth()
        .background(MaterialTheme.colors.background),
    contentPadding = PaddingValues(
        top = TabAnchorHeight,
        start = LazyColumnContentPadding,
        end = LazyColumnContentPadding
    ),
    verticalArrangement = Arrangement.spacedBy(18.dp),
    reverseLayout = false,
    state = lazyListState,
) {
    item { Title(topTitleText) }
    stickyHeader {
        TabAnchor(
            tabData = categoriesDirect,
            scrollState = lazyListState,
        )
    }
    ...
}

'Android > AAC' 카테고리의 다른 글

Kotlin Coroutine  (0) 2022.03.24
Compose의 State  (0) 2022.03.03
Jetpack - Compose  (0) 2021.10.28
Navigation  (1) 2021.08.13
DataBinding  (1) 2021.08.13