2022. 6. 24. 14:34ㆍAndroid
이번에 포스팅 주제는 Compose 를 실제로 적용해보기입니다.
저번에 Compose 작성 관련해서 포스팅 하였는데
그때는 Compose 란 무엇인가와 Compose 에 대한 저의 생각을 적은 글이였었습니다.
저런 글을 쓰고 그래도 한번 실제로 적용을 시켜봐야 신비성이 올라가기에
제가 지금 개인적으로 만들고있는 프로젝트에 한번 적용을 시켜보자 합니다.
기존 xml 화면을 먼저 보시겠습니다.
실제 화면은 이렇고
xml 코드는
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.taijoo.cookingassistance.view.storage_material_setting.StorageMaterialSettingViewModel" />
<variable
name="activity"
type="com.taijoo.cookingassistance.view.storage_material_setting.StorageMaterialSettingActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="@{()->activity.onBackgroundClick()}"
tools:context=".view.storage_material_setting.StorageMaterialSettingActivity">
<include
android:id="@+id/title_appbar"
layout="@layout/item_title_include"
app:TitleActivity="@{activity}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@{viewmodel.storageData.name}"
android:textColor="@color/color_000000"
android:textSize="20sp"
app:layout_constraintTop_toBottomOf="@+id/title_appbar"
tools:text="감자" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginTop="50dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintTop_toBottomOf="@+id/tv_name">
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="갯수 : "
android:textColor="@color/color_000000"
android:textSize="17sp"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/etSize"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:inputType="number"
android:imeOptions="actionDone"
android:text="@={``+viewmodel.storageData.size}"
android:textColor="@color/color_000000"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView6"
app:layout_constraintTop_toTopOf="parent"
tools:text="10" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{()->activity.onClickDate()}"
android:padding="10dp"
android:background="?attr/selectableItemBackground"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@+id/ll_size">
<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="구입한 날짜 : "
android:textColor="@color/color_000000"
android:textSize="17sp"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.storageData.date}"
android:textColor="@color/color_000000"
android:textSize="17sp"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView11"
app:layout_constraintTop_toTopOf="parent"
tools:text="10" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_edit_24"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/color_000000" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{()->activity.onClickExpirationDate()}"
android:padding="10dp"
android:background="?attr/selectableItemBackground"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@+id/ll_date"
tools:layout_editor_absoluteX="10dp">
<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="유통기한 : "
android:textColor="@color/color_000000"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="@{viewmodel.storageData.expiration_date}"
android:textColor="@color/color_000000"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView9"
app:layout_constraintTop_toTopOf="parent"
tools:text="10" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_edit_24"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/color_000000" />
</androidx.constraintlayout.widget.ConstraintLayout>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/custom_background_edittext"
android:gravity="start|top"
android:layout_marginTop="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:paddingStart="20dp"
android:paddingTop="10dp"
android:paddingEnd="20dp"
android:paddingBottom="10dp"
android:minHeight="300dp"
android:maxHeight="300dp"
android:textColor="@color/color_000000"
android:textSize="15sp"
android:hint="비고"
android:text="@={viewmodel.storageData.note}"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/color_000000"
android:text="저장"
android:textStyle="bold"
android:onClick="@{()->activity.onOkClick()}"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
흔히들 많이 쓰는 xml 방식에서 이번에는 Compose 로 바꾸어보겠습니다.
일단 Preview 로 봤을때 입니다.
거의 동일하게 UI를 제작 하였습니다
이제 코드를 보시죠
@Composable
fun Header(){
CookingAssistanceTheme{
Surface(color = MaterialTheme.colors.background) {
Row(modifier = Modifier
.fillMaxWidth()
.padding(5.dp, 5.dp, 5.dp, 5.dp)) {
Button(onClick = {} ,
colors = ButtonDefaults.buttonColors(Color.Transparent) , elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp ,
pressedElevation = 0.dp ,
disabledElevation = 0.dp
)
) {
Image(
painter = painterResource(id = R.drawable.ic_back_24) ,
contentDescription = "header" , colorFilter = ColorFilter.tint(
colorResource(id = R.color.color_000000)))
}
}
}
}
}
@Composable
fun Body(){
val focusManager = LocalFocusManager.current//배경 포커스 잡기
val focusRequester = FocusRequester()//버튼 포커스 잡기
val interactionSource = remember { MutableInteractionSource() }//버튼 포커스 잡기
val isFocused = interactionSource.collectIsFocusedAsState().value
Column(modifier = Modifier
.fillMaxHeight()
.addFocusCleaner(focusManager)) {
Column(modifier = Modifier.fillMaxWidth() , horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "제목" ,fontSize = 20.sp , color = colorResource(id = R.color.color_000000))
}
Column(modifier = Modifier
.fillMaxWidth()
.padding(20.dp, 50.dp, 20.dp, 10.dp)) {
Row {
Text(text = "갯수 : " , color = colorResource(id = R.color.color_000000) ,fontSize = 17.sp , modifier = Modifier
.align(
Alignment.CenterVertically
)
.padding(10.dp))
BasicTextField(value = "0", onValueChange ={} ,
Modifier
.fillMaxWidth()
.align(Alignment.CenterVertically) , textStyle = TextStyle(fontSize = 17.sp ,color = colorResource(
id = R.color.color_000000
)))
}
}
Column(modifier = Modifier
.fillMaxWidth()
.padding(20.dp, 20.dp, 20.dp, 10.dp)) {
Row {
Button(onClick = {
focusRequester.requestFocus()
},
modifier = Modifier
.focusRequester(focusRequester)
.focusable(interactionSource = interactionSource),
colors = ButtonDefaults.buttonColors(Color.Transparent) , elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp ,
pressedElevation = 0.dp ,
disabledElevation = 0.dp
) , contentPadding = PaddingValues(0.dp) ) {
Text(text = "구입한 날짜 : " , color = colorResource(id = R.color.color_000000) ,fontSize = 17.sp , modifier = Modifier
.align(
Alignment.CenterVertically
)
.padding(10.dp))
Text(text = "0 " , color = colorResource(id = R.color.color_000000) ,fontSize = 17.sp , modifier = Modifier
.align(
Alignment.CenterVertically
)
.weight(1f))
Image(painter = painterResource(id = R.drawable.ic_edit_24), contentDescription = "edit" , colorFilter = ColorFilter.tint(
colorResource(id = R.color.color_000000)) , modifier = Modifier.align(Alignment.CenterVertically))
}
}
}
Column(modifier = Modifier
.fillMaxWidth()
.padding(20.dp, 20.dp, 20.dp, 10.dp)) {
Row {
Button(onClick = {
},
colors = ButtonDefaults.buttonColors(Color.Transparent) , elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp ,
pressedElevation = 0.dp ,
disabledElevation = 0.dp
) , contentPadding = PaddingValues(0.dp)){
Text(text = "유통기한 : " , color = colorResource(id = R.color.color_000000) ,fontSize = 17.sp , modifier = Modifier
.align(
Alignment.CenterVertically
)
.padding(10.dp))
Text(text = "0 " , color = colorResource(id = R.color.color_000000) ,fontSize = 17.sp , modifier = Modifier
.align(
Alignment.CenterVertically
)
.weight(1f))
Image(painter = painterResource(id = R.drawable.ic_edit_24), contentDescription = "edit" , colorFilter = ColorFilter.tint(
colorResource(id = R.color.color_000000)) , modifier = Modifier.align(Alignment.CenterVertically))
}
}
}
Column(modifier = Modifier
.padding(20.dp, 30.dp, 20.dp, 0.dp)) {
TextField(value = "asdas", onValueChange = {} ,modifier = Modifier
.fillMaxWidth()
.defaultMinSize(minHeight = 300.dp)
.border(
width = 1.dp, shape = RoundedCornerShape(20.dp), color = colorResource(
id = R.color.color_DDDDDD
)
)
, colors = TextFieldDefaults.textFieldColors(focusedIndicatorColor = Color.Transparent , backgroundColor = Color.Transparent
, textColor = colorResource(id = R.color.color_000000) , unfocusedIndicatorColor = Color.Transparent) ,
textStyle = TextStyle(fontSize = 15.sp)
)
}
Spacer(modifier = Modifier.weight(1f))
Button(onClick = { /*TODO*/ } ,
modifier = Modifier.fillMaxWidth() , colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(
id = R.color.color_000000)) , elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp ,
pressedElevation = 0.dp ,
disabledElevation = 0.dp
)) {
Text(text = "저장" , color = colorResource(id = R.color.color_FFFFFF))
}
}
}
//백그라운드 포커스 잡기
fun Modifier.addFocusCleaner(focusManager: FocusManager, doOnClear: () -> Unit = {}): Modifier {
return this.pointerInput(Unit) {
detectTapGestures(onTap = {
doOnClear()
focusManager.clearFocus()
})
}
}
@Preview(showBackground = true , name = "Dark Mode" , uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun View(){
Column {
Header()
Body()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CookingAssistanceTheme {
Surface(color = MaterialTheme.colors.background) {
View()
}
}
}
}
일단 Header 와 Body 를 나누었습니다.
이유는 추후에 Compose 로 다시 UI 를 그릴때 Header 는 재사용을 위해 따로 Class 를 만들어 관리하고
나머지는 Body , View 는 해당 Class 안에 작성을 하였습니다
일단 순수하게 xml 과 Compose 로UI 만 짜봤을때 비교 소감은
아직 까지는 제가 Compose 를 많이 사용을 안하다보니 헷갈리는 부분들이 많더군요
예를 들면 Button 에 색상을 바꾸고자 한다면 xml 에서는
android:backgroundTint="@color/color_000000"
Compose 에서는
colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(
id = R.color.color_000000))
이런식으로 변경을 해야되더군요 제기준에서는 좀더 코드가 길어지긴합니다.
이부분 같은경우는 많이 사용법을 더 익힌다면 괜찮아 질거같습니다.
그래도 제기준에서 생각보다 편한점은 있었습니다
일반적으로 xml 에서 부모뷰를 보통은 ConstraintLayout , LinearLayout , RalativeLayout 을 많이 사용을 하는데
저는 ConstraintLayout , LinearLayout 이것 위주로 많이 사용합니다
그중에서도 LinearLayout 예전부터 쭉 써오던것이다보니
Compose 에 Row , Column 의 구동방식이랑 상당히 흡수해서 전체적인 UI 를 짜는데 그렇게 어렵지 않았습니다
아직은 더 디테일 하게 많이 써봐야 좀더 정확한 비교 분석을 할수있을거 같습니다.
다음시간에는 Compose 에 MVVM 적용시켜 데이터를 넣는 과정까지 진행해보겠습니다.
'Android' 카테고리의 다른 글
Android NDK 란? (0) | 2022.08.08 |
---|---|
Android Compose 적용 해보기 2 (0) | 2022.07.05 |
Android Compose 관하여 (0) | 2022.06.17 |
Android MVVM 아키텍처 패턴에 관하여 2 (0) | 2022.06.14 |
Android MVVM 아키텍처 패턴에 관하여 1 (0) | 2022.06.14 |