(6)-1 앱 기초 구조 구성해보기 - Netflix를 참고하여...

HEYDAY7·2022년 10월 18일
0

구조 결정하기

처음에 딱 생각났던 구조이다. 그냥 단순히 TopBar, BottomNavigationBar는 있어야 최소한 앱 같이 보인다는 생각을 조금은 갖고 있다. 여기서 어떻게 창의력을 발휘해볼까~ 고민해보며 여러 앱들을 켜보았다. 그러다가 가장 잘나가면서 좋은 예시를 찾았다. 바로 Netflix다.

내가 생각했던 거와 유사하게 TopBar, BottomNavigationBar를 가지고 있고 다루는 컨텐츠 또한 영화, TV series로 같기 때문에 이를 조금 참고해 CloneCoding의 형태로 만들어 볼 수 있을 것 같아 이런 형태로 결정했다.

CustomTopBar.kt

탑 바를 custom 하게 관리하려고 composable을 따로 만들었다. compose의 Layout을 이용하여 좀 더 세세하게 만들 수 있었지만, 이는 추후에 필요할 경우 만들기로 한다.

@Composable
fun CustomTopBar(
    color: Color = Color.Transparent,
    headContent: @Composable (() -> Unit)? = null,
    titleContent: @Composable () -> Unit,
    actionContent: @Composable (() -> Unit)? = null
) {
   Surface(color = color) {
       Row(
           modifier = Modifier
               .fillMaxWidth()
               .padding(horizontal = 12.dp)
               .requiredHeight(56.dp),
           verticalAlignment = Alignment.CenterVertically
       ) {
           if (headContent != null) {
               headContent()
               Spacer(modifier = Modifier.requiredWidth(12.dp))
           }
           Box(
               modifier = Modifier.weight(1f),
               contentAlignment = Alignment.CenterStart
           ) {
               titleContent()
           }
           if (actionContent != null) {
               Spacer(modifier = Modifier.requiredWidth(12.dp))
               actionContent()
           }
       }
   }
}

BottomNavigationBar

다음으로는 NavigationBar를 만들었다. 여러 탭들을 만들고 자연스럽게 이리저리 옮겨 다닐 수 있게 만들기 위해선 필수적인 composable이라 할 수 있고, 나는 이를 Scaffold 로 만들어 AppContent.kt에서 필요한 screen에만 사용해주었다.

## BottomNavigationBar.kt

@Composable
fun BottomNavigationScaffold(
    onHomeTabClick: () -> Unit,
    onSearchTabClick: () -> Unit,
    content: @Composable () -> Unit
) {
    Box(
        modifier = Modifier.fillMaxSize()
    ) {
        Box(
            modifier = Modifier.padding(bottom = 40.dp)
        ) {
            content()
        }
        BottomNavigationBar(
            onHomeTabClick = onHomeTabClick,
            onSearchTabClick = onSearchTabClick
        )
    }
}

@Composable
private fun BoxScope.BottomNavigationBar(
    onHomeTabClick: () -> Unit,
    onSearchTabClick: () -> Unit
) {
    Row(
        modifier = Modifier
            .align(Alignment.BottomCenter)
            .fillMaxWidth()
            .height(40.dp)
            .background(Color.Black)
    ) {
        BottomNavigationItem(
            tab = Tab.Home,
            onClick = onHomeTabClick
        )
        BottomNavigationItem(
            tab = Tab.Search,
            onClick = onSearchTabClick
        )
    }
}


@Composable
private fun RowScope.BottomNavigationItem(
    tab: Tab,
    onClick: () -> Unit,
) {
    Column(
        modifier = Modifier
            .weight(1f)
            .height(40.dp)
            .clickable { onClick() },
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(
            modifier = Modifier.requiredSize(20.dp),
            painter = painterResource(id = tab.icon),
            contentDescription = null,
            tint = Color.White
        )
        Spacer(modifier = Modifier.height(2.dp))
        Text(
            text = tab.title,
            color = Color.White
        )
    }
}

## AppContent.kt (이렇게 적용해주면 된다.)
#### 과거 코드
composable(
	route = "home"
) {
	CompositionLocalProvider(
    	provideHomeViewModelFactory { 
        	hiltViewModel<RealHomeViewModel>() 
        }
    ) {
    	HomeScreen()
    }
}

#### 수정한 코드
composable(
	route = "home"
) {
	CompositionLocalProvider(
    	provideHomeViewModelFactory { 
        	hiltViewModel<RealHomeViewModel>() 
        }
    ) {
    	BottomNavigationScaffold(
        	onHomeTabClick = {},
            onSearchTabClick = {
            	navController.navigate("search")
            }
        ) {
    		HomeScreen()
    	}
    }
}

## 요것도 AppContent.kt에 추가하기
enum class Tab(
    val title: String,
    val icon: Int
) {
    Home(title = "Home", icon = R.drawable.ic_home),
    Search(title = "Search", icon = R.drawable.ic_search)
}

이렇게 AppContent는 navController를 알고있기 때문에 바로 navigation callback을 넣어주면 쉽게 적용시킬 수 있다. 아직 아주 못생겼지만 잘 동작하는 걸 볼 수 있다. 또한 Tab 추가도 매우 간편해졌다.

마치며

오늘의 작업 결과를 코드는 요 branch에서 확인해 볼 수 있고, 앱 자체는 현재 아래와 같은 상태이다. 아직 텅텅 비어있지만 이제 Tab도 구축되었으니 쭉쭉 화면을 한번 그려나가 볼 일만 남았다. UI 자체를 단순히 그리는 일은 별로 어렵지 않을거라 예상되는데, API를 쓰고, 또 composition 관리를 해보며 어떠한 어려움을 마주하게 될지 궁금해진다. 그럼 이만.

참고

icon의 경우 FreeIcon이나 Flaticon을 이용하고 있다.

profile
(전) Junior Android Developer (현) Backend 이직 준비생

0개의 댓글