저번 시간에 이어 계속해서 Compose에 대해 작성하겠습니다.
Compose의 경우 Material Design 원칙을 지원하도록 빌드되었습니다.
Material Design이란? :
Material Design은 플랫폼 및 기기 전반의 시각적 요소, 모션 및 상호작용 디자인을 위한 포괄적인 가이드 입니다. 대표적으로 애플리케이션 내에서 다크 모드를 지원하는 부분과 버튼 클릭의 애니메이션 동작과 같은 것들이 Material Design이라고 할 수 있습니다.
Jetpack Compose는 머티리얼 디자인 및 UI 요소를 즉시 사용가능하도록 구현합니다. Material Design 스타일 지정을 사용하여 MessageCard의 디자인을 개선해보는 코드를 작성해보겠습니다.
Base Code
// ...
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTutorialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
MessageCard(Message("Android", "Jetpack Compose"))
}
}
}
}
}
@Preview
@Composable
fun PreviewMessageCard() {
ComposeTutorialTheme {
Surface {
MessageCard(
msg = Message("Colleague", "Take a look at Jetpack Compose, it's great!")
)
}
}
}
MaterialTheme.colors를 사용하여 래핑된 테마의 색상으로 스타일을 지정할 수 있습니다.
여기에서는 제목 스타일을 지정하고 이미지에 테두리를 추가합니다.
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = msg.author,
color = MaterialTheme.colors.secondaryVariant
)
Spacer(modifier = Modifier.height(4.dp))
Text(text = msg.body)
}
}
}
Material 서체 스타일은 MaterialTheme에서 사용할 수 있으며, Text 컴포저블에 추가하기만 하면 됩니다.
// ...
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = msg.author,
color = MaterialTheme.colors.secondaryVariant,
style = MaterialTheme.typography.subtitle2
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = msg.body,
style = MaterialTheme.typography.body2
)
}
}
}
Shape을 사용하여 최종 터치를 추가할 수 있습니다. 먼저 Surface 컴포저블을 중심으로 메시지 본문 테스트를 래핑합니다. 이렇게 하면 메시지 본문의 도형과 높이를 맞춤설정할 수 있습니다. 추가적으로 메시지에 패딩도 추가할 수 있습니다.
// ...
import androidx.compose.material.Surface
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
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(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
style = MaterialTheme.typography.body2
)
}
}
}
}
어두운 테마의 경우 기기 배터리 절약 및 OLED 디스플레이 번인 현상, 어두운 환경에서의 사용들을 위해 자주 사용합니다. Jetpack Compose는 기본적으로 어두운 테마를 처리할 수 있습니다. 머티리얼 디자인 색상, 텍스트, 배경을 사용하면 어두운 배경에 맞춰 자동으로 조정됩니다.
// ...
import android.content.res.Configuration
@Preview(name = "Light Mode")
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,
name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
ComposeTutorialTheme {
Surface {
MessageCard(
msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
)
}
}
}
메시지를 주고 받다 보면 여러 메서지 전송 기록들을 볼 수 있습니다. LazyColumn과 LazyRow를 사용합니다. 이러한 컴포저블은 화면에 표시되는 요소만 렌더링하므로 긴 목록에 매우 효율적으로 설계되었습니다.
LazyColumn에 items 하위 요소가 있음을 할 수 있고 List를 매개변수로 가져오고 람다는 Message의 인스턴스인 message라는 매개변수를 수신합니다.
// ...
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@Composable
fun Conversation(messages: List<Message>) {
LazyColumn {
items(messages) { message ->
MessageCard(message)
}
}
}
@Preview
@Composable
fun PreviewConversation() {
ComposeTutorialTheme {
Conversation(SampleData.conversationSample)
}
}
메시지 종류중에서 일정 글 이상이 작성되어 있다면 가려지며 해당 내용을 보고 싶다면 터치를 통해 해당 메시지 칸을 확장하여 보게됩니다. Compose에서 그러한 기능을 수행할 수 있습니다.
// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTutorialTheme {
Conversation(SampleData.conversationSample)
}
}
}
}
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
// We keep track if the message is expanded or not in this
// variable
var isExpanded by remember { mutableStateOf(false) }
// We toggle the isExpanded variable when we click on this Column
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(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
// If the message is expanded, we display all its content
// otherwise we only display the first line
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.body2
)
}
}
}
}
https://developer.android.com/jetpack/compose/tutorial?hl=ko