Android-jetpack Compose
jackpack compose - text extended by click
slow333
2023. 2. 21. 17:41
이 단계에서는 이미 알고 있는 내용을 적용하고 몇 가지 힌트만 사용하여 새로운 개념을 학습합니다. 다음과 같이 만들어 보겠습니다.
버튼을 아이콘으로 대체
- 하위 요소인 Icon과 함께 IconButton 컴포저블을 사용합니다.
- Icons.Filled.ExpandLess와 Icons.Filled.ExpandMore를 사용합니다. 이는 material-icons-extended 아티팩트에서 사용할 수 있습니다. app/build.gradle 파일의 종속 항목에 다음 줄을 추가합니다.
implementation "androidx.compose.material:material-icons-extended:$compose_version"
- 정렬을 고정하기 위해 패딩을 수정합니다.
- 접근성을 위해 콘텐츠 설명을 추가합니다(아래 '문자열 리소스 사용' 참고).
문자열 리소스 사용
'더보기' 및 '간략히 보기'를 위한 콘텐츠 설명이 있어야 하며 간단한 if 문을 사용하여 설명을 추가할 수 있습니다.
contentDescription = if (expanded) "Show less" else "Show more"
하지만 문자열을 하드 코딩하는 것은 바람직하지 않으며 strings.xml 파일에서 이러한 문자열을 가져와야 합니다.
이를 자동으로 하려면 Android 스튜디오의 'Context Actions'에서 사용할 수 있는 'Extract string resource'를 각 문자열에 사용하면 됩니다.
또는 app/src/res/values/strings.xml을 열고 다음 리소스를 추가합니다.
<string name="show_less">Show less</string>
<string name="show_more">Show more</string>
더보기
각 카드의 크기 변경이 트리거되면 'Composem ipsum' 텍스트가 표시되고 사라집니다.
- 항목을 펼칠 때 표시되는 Greeting 내부의 Column에 새로운 Text를 추가합니다.
- extraPadding을 삭제하고 대신 animateContentSize 수정자를 Row에 적용합니다. 그러면 애니메이션 생성 프로세스가 자동화되고 이를 수동으로 실행하기가 어려워집니다. 또한 coerceAtLeast가 더 이상 필요하지 않습니다.
고도 및 도형 추가
- shadow 수정자를 clip 수정자와 함께 사용하여 카드 스타일을 만들 수 있습니다. 그러나 이를 정확하게 실행하는 Material 컴포저블(Card)이 있습니다. CardDefaults.cardColors를 호출하고 변경하려는 색상을 재정의하여 Card의 색상을 변경할 수 있습니다.
최종 코드
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons.Filled
import androidx.compose.material.icons.filled.ExpandLess
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.codelab.basics.ui.theme.BasicsCodelabTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BasicsCodelabTheme {
MyApp(modifier = Modifier.fillMaxSize())
}
}
}
}
@Composable
fun MyApp(modifier: Modifier = Modifier) {
var shouldShowOnboarding by rememberSaveable { mutableStateOf(true) }
Surface(modifier, color = MaterialTheme.colorScheme.background) {
if (shouldShowOnboarding) {
OnboardingScreen(onContinueClicked = { shouldShowOnboarding = false })
} else {
Greetings()
}
}
}
@Composable
fun OnboardingScreen(
onContinueClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Welcome to the Basics Codelab!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onContinueClicked
) {
Text("Continue")
}
}
}
@Composable
private fun Greetings(
modifier: Modifier = Modifier,
names: List<String> = List(1000) { "$it" }
) {
LazyColumn(modifier = modifier.padding(vertical = 4.dp)) {
items(items = names) { name ->
Greeting(name = name)
}
}
}
@Composable
private fun Greeting(name: String) {
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primary
),
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
) {
CardContent(name)
}
}
@Composable
private fun CardContent(name: String) {
var expanded by remember { mutableStateOf(false) }
Row(
modifier = Modifier
.padding(12.dp)
.animateContentSize(
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
)
) {
Column(
modifier = Modifier
.weight(1f)
.padding(12.dp)
) {
Text(text = "Hello, ")
Text(
text = name, style = MaterialTheme.typography.headlineMedium.copy(
fontWeight = FontWeight.ExtraBold
)
)
if (expanded) {
Text(
text = ("Composem ipsum color sit lazy, " +
"padding theme elit, sed do bouncy. ").repeat(4),
)
}
}
IconButton(onClick = { expanded = !expanded }) {
Icon(
imageVector = if (expanded) Filled.ExpandLess else Filled.ExpandMore,
contentDescription = if (expanded) {
stringResource(R.string.show_less)
} else {
stringResource(R.string.show_more)
}
)
}
}
}
@Preview(
showBackground = true,
widthDp = 320,
uiMode = UI_MODE_NIGHT_YES,
name = "DefaultPreviewDark"
)
@Preview(showBackground = true, widthDp = 320)
@Composable
fun DefaultPreview() {
BasicsCodelabTheme {
Greetings()
}
}
@Preview(showBackground = true, widthDp = 320, heightDp = 320)
@Composable
fun OnboardingPreview() {
BasicsCodelabTheme {
OnboardingScreen(onContinueClicked = {})
}
}
@Preview
@Composable
fun MyAppPreview() {
BasicsCodelabTheme {
MyApp(Modifier.fillMaxSize())
}
}