티스토리 뷰

728x90

 

2022.06.29 - [안드로이드] - Compose 기초 1 : Column, Row, Box

 

Compose 기초 1 : Column, Row, Box

1. Compose <?xml version="1.0" encoding="utf-8"?> ... 기존의 안드로이드에서 UI는 위와 같이 xml을 이용해서 구현 할 수 있었습니다. 기본적으로 구현하는 방식은 전체를 Layout으로 감싸고 그 안에 각종 Vie..

alanboyce.tistory.com

이전 글 에이어서 Compose 기초 사용 방법에 대해 알아보겠습니다.

 

1. Text

Text(text = "Hello Android")

가장 기본적인 Text 사용 방법입니다.

Text(
    text = stringResource(id = R.string.dummy_short_text),
    maxLines = 2,
    overflow = TextOverflow.Ellipsis,
    color= Color.White,
    style = TextStyle(
        textAlign = TextAlign.Start,
        textDecoration = TextDecoration.combine(
            listOf(
                TextDecoration.Underline,
                TextDecoration.LineThrough
            )
        )
    ),
    letterSpacing = 5.sp,
    fontWeight = FontWeight.ExtraBold,
    fontSize = 22.sp,
    fontFamily = FontFamily(Font(R.font.nanum_gothic_bold)),
    lineHeight = 40.sp,
    modifier = Modifier
        .fillMaxWidth()
        .background(Color.Black),
    onTextLayout = {
        Log.d("TAG", "${it.lineCount}")
    }
)

각 종 매개변수 사용을 해 보았습니다.

이걸 일일이 다하기에는 너무 많고 사용해 보면 쉽게 알 수 있는 부분이라 대부분은 생략하겠습니다.

string에 정의된 문구를 사용하기 위해서는 stringResorce를 사용합니다.

overflow는 Text영역을 벗어났을 때 어떻게 표기할지를 결정합니다. Ellipsis를 하면 마지막에... 을 보여줍니다.

style은 Text의 각종 속성들을 TextStyle을 통해 지정합니다. 변수로 사용 가능 함으로 다른 곳에서 미리 지정을 해 두고 사용하시면 됩니다.

onTextLayout은 (TextResult) -> Unit으로 필요에 따라 아래의 값들을 사용할 수 있습니다.

 

2. Image

Image(
    painter = painterResource(id = R.drawable.ic_launcher_background),
    contentDescription = "description"
)

drawable에 있는 이미지는 위와 같이 사용할 수 있습니다.

Image(
    imageVector = Icons.Default.Edit,
    contentDescription = "description",
    modifier = Modifier.size(100.dp)
)

imageVector의 경우 위와 같이 사용이 가능합니다.

크기 조정할 때에는 Modifier를 이용하면 됩니다.

Glide의 경우 준비가 필요합니다.

우선 상태 값을 저장할 Seald Class를 만들어 줍니다.

sealed class UiState {
    object Loading : UiState()
    data class Success(val data: Bitmap) : UiState()
}

 

@Composable
fun loadPicture(url: String): MutableState<UiState> {
    val state : MutableState<UiState> = mutableStateOf(UiState.Loading)

    Glide.with(LocalContext.current)
        .asBitmap()
        .load(url)
        .into(object : CustomTarget<Bitmap>(){
            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                state.value = UiState.Success(resource)
            }
            override fun onLoadCleared(placeholder: Drawable?) {}
        })

    return state
}

그다음 상태 변화에 따라 로딩, 이미지를 저장을 하여 리턴하는 함수를 만들어줍니다.

val state = loadPicture(url = "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/133.png")
when (state.value) {
    is UiState.Loading -> {
        CircularProgressIndicator()
    }
    is UiState.Success -> {
        Image(bitmap = (state.value as UiState.Success).data.asImageBitmap(), contentDescription = null)
    }
}

마지막으로 상태 값에 따라 UI를 그려주면 끝입니다.

 

다른 방법은 skydoves님께서 만드신 라이브러리를 사용하는 것입니다.

https://github.com/skydoves/landscapist

 

GitHub - skydoves/landscapist: 🍂 Jetpack Compose image loading library that fetches and displays network images with Glide, C

🍂 Jetpack Compose image loading library that fetches and displays network images with Glide, Coil, and Fresco - GitHub - skydoves/landscapist: 🍂 Jetpack Compose image loading library that fetches a...

github.com

build.gradle에 아래의 내용을 추가해줍니다.

implementation "com.github.skydoves:landscapist-glide:1.5.2"
GlideImage(
    imageModel = "https://user-images.githubusercontent.com/24237865/127760344-bb042fe8-23e1-4014-b208-b7b549d32086.png",
    loading = { CircularProgressIndicator() },
    failure = {
        Text(text = "이미지 로드에 실패하였습니다.")
    }
)

이렇게만 하면 간단하게 Glide를 사용할 수 있습니다.

다양한 사용법에 관해서는 링크를 참조해주세요

 

3. LazyColumn/LazyRow + Card

LazyColumn과 LazyRow는 ListView나 RecyclerView와 같이 여러 개의 아이템을 리스트로 보여줍니다.

우선 반복되는 UI의 아이템을 만들어줍니다.

@Composable
fun ListItem(name: String) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(10.dp),
        elevation = 10.dp,
        shape = RoundedCornerShape(12.dp)
    ) {
        Row(
            modifier = Modifier.padding(15.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Box(
                modifier = Modifier
                    .clip(CircleShape)
                    .background(Color(0xFFFF7043))
                    .size(width = 50.dp, height = 50.dp)
            )
            Spacer(modifier = Modifier.padding(10.dp))
            Text(text = name)
        }
    }
}

Card는 기존의 CardView와 거의 유사하며 CardView의 속성들을 대부분 넣을 수 있다고 생각하시면 됩니다.

Box에서 clip을 사용했는데 이것을 활용하면 원하는 모형으로 자르실 수 있습니다.

Spacer는 빈 공간을 만들어주는 역할을 합니다. 저는 padding을 썼지만 size를 사용하셔도 결과는 똑같습니다.

Compose는 margin속성이 없어서 padding 속성 주기 애매한 경우 사용하면 됩니다.

 

아이템을 준비하였으니 다음은 리스트 준비를 합니다.

LazyColumn / LazyRow의 경우 별도로 어뎁터는 필요 없습니다

val list = (1..10).map { "${it}번째 아이템" }

간단하게 위와 같이 준비를 하였습니다.

Column() {
    LazyRow(content = {
        items(list) {
            ListItem(it)
        }
    })

    LazyColumn(
        content = {
            items(list) { item ->
                ListItem(item)
            }
        },
        verticalArrangement = Arrangement.spacedBy(10.dp)
    )

}

Column 또는 Row의 속성을 이용해서 간격을 벌릴 수도 있습니다.

만약 리스트에 내용이 변경되어야 한다고 하면 list를 MutableState로 만들어서 list의 값을 변경하면 됩니다.

728x90
댓글