https://developer.android.com/courses/pathways/compose

Jetpack Compose Tutorial입니다.

공식문서를 해석하며 Jetpack Compose를 학습합니다.

Jetpack Compose Basics

@Composable 을 이용하여 앱의 구성을 정의한다.

@Composable 위에 @PREVIEW 를 달아주면 미리보기가 가능하다.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
                MessagingCard(name = "KOTLIN")
        }
    }
}

@Composable
fun MessagingCard(name:String){
    Text(text = "Hello ${name}!!!")
}   

@Preview
@Composable
fun PreviewMessageCard() {
    MessagingCard("Android")
}

레이아웃

여러개의 텍스트를 추가할때는 dataClass 를 이용하여 매개변수로 넣어준다.

data class Message(val author : String,val body : String)
@Composable
fun MessagingCard(msg:Message){
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessagingCard(
        msg = Message("Colleague","Hey, take a look at Jetpack Compose, it's great!"))
}

이렇게 만들면 텍스트에 대한 정렬 방식이 선언되지 않았기 때문에 두개의 텍스트가 겹치게된다.


열 사용

Column기능을 사용하면 요소를 세로로 정렬할 수 있다. Row를 사용하여 항목을 가로로 정렬할 수 있으며 Box를 사용하여 요소를 쌓을 수 있다.

@Composable
fun MessagingCard(msg:Message){
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessagingCard(
        msg = Message("Colleague","Hey, take a look at Jetpack Compose, it's great!"))
}

Image를 가져올때는 리소스관리자를 이용하여 가져올 수 있다.


이미지 요소 추가

@Composable
fun MessagingCard(msg:Message){
    Row {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = "Contact profile picture"
        )
        Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
    }
}

레이아웃 구성

요소의 간격을 조절할 수 있다. Compose는 modifiers를 사용한다. 이는 컴포저블(=요소)의 크기,레이아웃,모양을 변경하거나 요소를 클릭가능하게 만드는 것과 같은 상위 수준 상호 작용을 추가할 수 있습니다.

@Composable
fun MessagingCard(msg: Message) {

//modifier를 추가해준다.
//Modifier.padding을 이용하여 padding을 설정한다.매개변수로 
//start = all,top = all,end = all,bottom = all 을 받을 수 있다.

  Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = "Contact profile picture",
//Image의 매개변수에 modifier를 선언해 준다.
//.size를 통하여 이미지의 크기를 조절한다.
//clip을 통하여 모양을 정할 수 있다.
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
        )

//Size 메서드 내부는 다음과 같다.
//fun Modifier.size(size: Dp) = this.then(
//    SizeModifier(
//        minWidth = size,
//       maxWidth = size,
//        minHeight = size,
//        maxHeight = size,
//        enforceIncoming = true,
//        inspectorInfo = debugInspectorInfo {
//            name = "size"
//            value = size
//        }
//    )
//)

//clip의 내부는 다음과 같으며 Shape의 종류는 circle,rectangle과 같은 모양부터 button까지 너무 많으므로 추후에 정리하자.
//fun Modifier.clip(shape: Shape) = graphicsLayer(shape = shape, clip = true)

//Spacer를 통하여 빈 공간을 넣어준다. margin이라고 생각할 수도 있고, 이전의 안드로이드에서 View를 이용한 빈 공간이라고도 생각된다.
//2개를 동시에 적용하려면
//Spacer(modifier = Modifier.width(100.dp).height(100.dp))
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}

머터리얼 디자인

Compose는 머티리얼 디자인 원칙을 지원한다.

머티리얼 디자인 사용

Jetpack Compose는 기본적으로 Material Design 및 해당 UI 요소의 구현을 제공합니다. 
머티리얼 디자인 스타일을 사용하여 MessageCard 컴포저블의 모양을 개선할 것입니다.
시작하려면 이 경우 MessageCard프로젝트에서 생성된 Material 테마로 함수를 래핑합니다
함수 에서 ComposeTutorialTheme모두 수행하십시오.@PreviewsetContent

머티리얼 디자인은 색상, 타이포그래피, 모양의 세 가지 기둥을 중심으로 구성됩니다. 하나씩 추가해보자

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PracticejetpackTheme {
                MessagingCard(Message("Android", "Jetpack Compose"))
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    PracticejetpackTheme {
        MessagingCard(
            msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
        )
    }
}

색깔

래핑된 테마의 색상으로 스타일을 지정하는 것은 쉽고 색상이 필요한 모든 곳에서 테마의 값을 사용할 수 있습니다.

제목의 스타일을 지정하고 이미지에 테두리를 추가해 보겠습니다.

@Composable
fun MessagingCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
//border를 이용하면 해당 이미지에 테두리를 넣어 줄 수 있다. 두께와 색, 그리고모양을 넣어준다.
                **.border(4.dp,MaterialTheme.colors.secondary, RectangleShape)**
        )
        Spacer(modifier = Modifier
            .width(100.dp)
            .height(100.dp))

        Column {
            Text(text = msg.author,
//setTextColors와 같은 역할을 한다. Text의 매개변수에 넣어주면 된다.
            **color = MaterialTheme.colors.secondaryVariant
            )**
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}

타이포그래피

Material Typography 스타일은 MaterialTheme에서 사용할 수 있으며, Text 컴포저블에 추가하기만 하면 됩니다.

@Composable
fun MessagingCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(4.dp, MaterialTheme.colors.secondary, RectangleShape)
        )
        Spacer(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
        )

        Column {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
//style이라는 매개변수에 지정해준다.
                **style = MaterialTheme.typography.subtitle2**
            )
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body,
                **style = MaterialTheme.typography.subtitle1**
						)
        }
    }
}
//typography의 요소들은 다음과 같이 있으며 기본값이다. 추가적으로 유저가 설정할 수 있다.
//class Typography internal constructor(
//    val h1: TextStyle,
//    val h2: TextStyle,
//    val h3: TextStyle,
//    val h4: TextStyle,
//    val h5: TextStyle,
//    val h6: TextStyle,
//   val subtitle1: TextStyle,
//    val subtitle2: TextStyle,
//    val body1: TextStyle,
//    val body2: TextStyle,
//    val button: TextStyle,
//    val caption: TextStyle,
//    val overline: TextStyle
//)

모양

@Composable
fun MessagingCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(4.dp, MaterialTheme.colors.secondary, RectangleShape)
        )
        Spacer(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
        )

        Column {
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )
            Spacer(modifier = Modifier.height(4.dp))

//shape를 통하여 텍스트 영역을 라운드로 감쌀수 있으며 기본 바탕색이 지원뙨다.
            **Surface(shape = MaterialTheme.shapes.medium, elevation = 1.dp) {**
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    style = MaterialTheme.typography.body2
                )
            }
        }
    }
}
//Shaps 클래스를 보면 다음과 같이 되어있다.
//class Shapes(
    /**
     * Shape used by small components like [Button] or [Snackbar]. Components like
     * [FloatingActionButton], [ExtendedFloatingActionButton] use this shape, but override
     * the corner size to be 50%. [TextField] uses this shape with overriding the bottom corners
     * to zero.
     */
//    val small: CornerBasedShape = RoundedCornerShape(4.dp),
    /**
     * Shape used by medium components like [Card] or [AlertDialog].
     */
//    val medium: CornerBasedShape = RoundedCornerShape(4.dp),
    /**
     * Shape used by large components like [ModalDrawer] or [ModalBottomSheetLayout].
     */
//    val large: CornerBasedShape = RoundedCornerShape(0.dp)
//)

다크테마 지원

기본적으로 Compose는 다크테마를 지원하며 다크테마 설정시 자동적으로 색상을 바꿔줍니다.

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
    PracticejetpackTheme {
        MessagingCard(
            msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
        )
    }
}

목록 및 애니메이션

메시지 목록 만들기

하나의 메시지로 대화하는 것은 조금 외로운 느낌이 드니, 대화를 하나 이상의 메시지로 바꿔보자. Conversation여러 메시지를 표시 하는 함수를 만들어야 합니다. 이 사용 사례의 경우 Compose LazyColumn및 LazyRow이러한 구성 가능 요소는 화면에 표시되는 요소만 렌더링하므로 긴 목록에 대해 매우 효율적으로 설계되었습니다. 동시에 RecyclerViewXML 레이아웃의 복잡성을 피할 수 있습니다.

LazyColumn이 코드 조각에서 항목 하위 항목이 있는 것을 볼 수 있습니다 . List매개변수로 사용하고 해당 람다는 의 인스턴스인 이름을 지정한 매개변수 ( message원하는 대로 이름을 지정할 수 있음)를 Message받습니다. 간단히 말해서 이 람다는 제공된 의 각 항목에 대해 호출됩니다 List. 이 샘플 데이터세트 를 프로젝트로 가져와서 대화를 빠르게 부트스트랩할 수 있습니다.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            PracticejetpackTheme {
                Column() {
                    MessagingCard(Message("Android", "Jetpack Compose"))
                    Conversation(SampleData.conversationSample)
                }
            }
        }
    }
}

//매개변수로 메세지를 받습니다. MessagingCard()의 매개변수.
//LazyColumn을 선언하므로써 하위 항목이 있다는 것을 알 수 있고, List형식의 매개변수를 받습니다.
//이 람다는 List의 각 항목에 대해 호출이 됩니다.forEach와 비슷함.
@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessagingCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    PracticejetpackTheme {
        Conversation(SampleData.conversationSample)
    }
}

부가 기능(애니메이션)

@Composable
fun MessagingCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

//메서드 안에 isExpanded 선언. 
//remember는 람다식 내부의 값을 기억하고 있습니다.
//상태 변경을 추적합니다. 메모리에 로컬 상태를 저장하고 추적합니다.
//값이 변경될 때마다 자동적으로 다시 그려집니다.
        **var isExpanded by remember { mutableStateOf(false) }**

//Column안의 요소에게 clickable를 통하여 클릭이 가능하게 변경합니다.
        **Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {**
            Text(
                text = msg.author,
                color = MaterialTheme.colors.secondaryVariant,
                style = MaterialTheme.typography.subtitle2
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                elevation = 1.dp,
            ) {
//text의 요소입니다.
//isExpanded에 따라 maxLines를 변경해줍니다.
                **Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.body2
                )**
            }
        }
    }
}
profile
러닝커브를 따라서 등반중입니다.

0개의 댓글