Devfest Korea week 1-1 Compose Basic
Devfest Korea를 참여하면서 정리하게 된 글이다.
컴포즈가 필요한 이유
Compose가 태어나기전 지난 역사들
보통 앱을 만든다하면 XML에서 UI를 그리고 이어진 Class에서 프로그래밍을 했다.
그리고 XML에의 UI를 접근하려면 find를 통해 찾아야하는 무식한 방법을 썼다.
지금 생각해보면 어떻게 코딩했나 싶다..
이것의 문제점은 UI에서 컨트롤할 객체들이 많아지면 많아질수록 선언해야할게 많아지는것이다.
이러한것을 타개하기위해 구글은 DataBinding
해결책을 냈다.
좀더 코딩이 쉬워졌다. 더이상 ID를 찾을수없다는 에러가 종식되었다.
이것까지가 현재의 시점이다.
쓰다보니 기존적인 문제점은 탈피하지 못했다.
- UI와 작동 코드가 분리되어있다는 문제
- UI를 컨트롤하는 세팅과정중 불필요한 보일러 플레이트 코드 생성
Fragment
의 까다로운 생명주기
컴포즈 시작하기
더이상 SetContent
에 binding.root
를 안붙여도 된다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BasicsCodelabTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
@Composable
private fun Greeting(name: String) {
Surface(color = MaterialTheme.colors.primary) {
Text (text = "Hello $name!")
}
}
Surface
는 컴포넌트들을 Wrap한다고 볼수있다.
테마를 입힌다거나 클릭이벤트를 이곳에서 줄수도있다.
열과 행 만들기
Compose의 표준 레이아웃은 Column
, Row
및 Box
이다.
@Composable
private fun Greeting(name: String) {
Surface(
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier.weight(1f)) {
Text(text = "Hello, ")
Text(text = name)
}
OutlinedButton(
onClick = { /* TODO */ }
) {
Text("Show more")
}
}
}
}
Surface
를 통해 수직 4dp , 수평 8dp를 적용했다.
텍스트와 버튼을 양쪽에 적용하기 위해 Row
를 넣고,
weight
를 통해 반반을 적용했다.
상태 적용하기
show less
를 클릭할경우, 확장이 되어야 한다.
@Composable
private fun Greeting(name: String) {
var expanded = false // Don't do this!
Surface(
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier.weight(1f)) {
Text(text = "Hello, ")
Text(text = name)
}
OutlinedButton(
onClick = { expanded = !expanded }
) {
Text(if (expanded) "Show less" else "Show more")
}
}
}
}
이렇게 코드를 짤경우, 아무런 반응이 없다.
Compose
는 상태를 observe
하고, 변경이 될경우 UI를 업데이트하는데,
단순한 Boolean
값은 업데이트하지 않는다.
해결책은 mutableStateOf
를 적용하는 것이다.
@Composable
private fun Greeting(name: String) {
val expanded = remember { mutableStateOf(false) }
val extraPadding = if (expanded.value) 48.dp else 0.dp
Surface(
color = MaterialTheme.colors.primary,
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
Row(modifier = Modifier.padding(24.dp)) {
Column(modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding)
) {
Text(text = "Hello, ")
Text(text = name)
}
OutlinedButton(
onClick = { expanded.value = !expanded.value }
) {
Text(if (expanded.value) "Show less" else "Show more")
}
}
}
}
단순히 mutableStateOf
를 적용할 경우, UI가 업데이트 될때마다
계속 false를 호출시킬것이다.
remember
를 호출하면 업데이트 되어도 값을 유지할 수 있다.
레이아웃 숨기기
Layout
을 숨길때 , 우리는 visible
과 invisible
을 이용한다.
Compose
에서는 이러한 기능을 제공하지 않고, 코드로 표현을 해줘야한다.
fun MyApp(){
var shouldShowOnboarding by remember { mutableStateOf(true) }
if (shouldShowOnboarding) {
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
} else {
Greetings()
}
}
// OnboardingScreen
@Composable
fun OnboardingScreen(onContinueClicked: () -> Unit) {
Surface {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Welcome to the Basics Codelab!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onContinueClicked
) {
Text("Continue")
}
}
}
}
숨겨야하는 레이아웃을 함수로 만들었을때, 클릭이벤트를 설정해야하는데,
MyApp()
에서는 클릭이벤트를 그냥 전달받을수 없기 때문에,
Listner
를 만들어줘야한다.
onContinueClicked: () -> Unit
이것을 이용해
Listner 파라미터를 만들어서
Button
의 OnClick
을 이용하여 Listner를 받는다.
클릭할 경우, 아래의 Listner
가 실행되는것이다.
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
RecycleView 이용하기
위의 Greetings
를 100번실행시키면 어떻게 될까?
ListView
가 사라진 이유가, OutOfMemory
에 대한 이슈 때문이다.
1000개를 보여줘야하는데 대략 500개가 넘어가버리면 핸드폰의 메모리가 터져버리는것이다.
이와 같이, Compose에서는 Lazy를 이용하여 RecycleView를 만들수 있다.
@Composable
private fun Greetings(names: List<String> = List(1000) { "$it" } ) {
LazyColumn(modifier = Modifier.padding(vertical = 4.dp)) {
items(items = names) { name ->
Greeting(name = name)
}
}
}
item
이라는 함수를 이용하여, 가져오기를 수행할수있다.
현재 name
이라는 명칭을 만들어, Greeting
에 파라미터를 던져주는것을 볼수있다. (DTO클래스일경우가 일반적이다.)
앱 종료시, 상태 저장하기
우리는 앱에 만들때마다 lifecycle에 생각해야한다.
핸드폰에서 회전하기, 다크모드 등 앱이 종료되서 다시 onCreate
로 실행되는 경우가 많다.
이 경우, 데이터가 초기화되고 레이아웃또한 원상태로 돌아가는데,
이상태를 막기위해, MVVM
패턴과 saveState
를 적용하였다.
ViewModel의 저장된 상태 모듈
savedstatehandle을 이용하는법
아직 ViewModel을 들어가지 않아서 모르겠지만,
기본적으로 간단하게 rememberSaveable
을 이용하여 값을 저장할수있다.
var shouldShowOnboarding by rememberSaveable { mutableStateOf(true) }
애니메이션 만들기
밋밋하다. 요즘 트랜가 간편이 최소화라지만, 애니메이션을 넣어주고싶다.
회사 업무에서 애니메이션을 넣은적이 없지만, Compose에서나마 꿈을 이룰수 있었다.
@Composable
private fun Greeting(name: String) {
var expanded by remember { mutableStateOf(false) }
val extraPadding by animateDpAsState(
if (expanded) 48.dp else 0.dp,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
)
Surface(
...
Column(modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding.coerceAtLeast(0.dp))
...
)
}
animateDpAsState()
는 애니메이션이 끝날때까지 값이 지속적으로 업데이트 되는 객체이다.
animateDpAsState
는 animationSpec
을 optional
하게 받는데 상세하게 애니메이션을 정의해줄수 있다.
테마 수정하기
private val DarkColorPalette = darkColors(
surface = Blue,
onSurface = Navy,
primary = Navy,
onPrimary = Chartreuse
)
private val LightColorPalette = lightColors(
surface = Blue,
onSurface = Color.White,
primary = LightBlue,
onPrimary = Navy
)
@Composable
fun BasicsCodelabTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
content = content
)
}
theme.kt
에서 다크모드가 될 경우나 혹은 기본적인 navy색깔을 변경할 경우, 위의 DarkColorPalette
와 LightColorPalette
의 수정으로 변경이 가능하다.
또한 어떤 컴포넌트에서 수정이 가해질때,
Text(text = name, style = MaterialTheme.typography.h4)
style을 사용한다.
그리고 기존 색상이나 스타일에서 살짝 바꿔야할 경우 copy
를 사용한다.
// 현재 h4의 유형에서 굵기를 굵게하기위해 copy를 썼다.
Text(
text = name,
style = MaterialTheme.typography.h4.copy(
fontWeight = FontWeight.ExtraBold
)
)
Author And Source
이 문제에 관하여(Devfest Korea week 1-1 Compose Basic), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@vov3616/Devfest-Korea-week1-Compose-Basic저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)