Android Compose 적용 해보기 1

2022. 6. 24. 14:34Android

반응형

이번에 포스팅 주제는 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