Text는 컴포즈를 시작하면 가장 처음으로 접하지 않을까 싶다!
(text를 작성한 줄 알고 있다가 이제서야 알게되어 작성하게 되었다😅)
그럼 Text에 대해 하나씩 알아가보자!
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current
)
1. text, color
text는 당연히 보여줄 string 값이고, color는 글자색이다.
Text(
text = "Hello $name!",
color = Color.Red
)
2. fontSize, fontStyle, fontWeight, fontFamily
fontSize는 size값으로 sp를 쓰게된다.
dp를 쓰게 되면 에러가 나는데 fontSize는 TextUnit값이 들어가야하고, 이 TextUnit은 3가지의 값이 있다.
internal val TextUnitTypes =
arrayOf(TextUnitType.Unspecified, TextUnitType.Sp, TextUnitType.Em)
sp와 em을 기본적으로 사용할 수 있기 때문에 xml에서 자유롭게(?) 사용할 수 있었던 dp는 사용이 불가하다.
안드로이드 디벨로퍼에서도 sp 또는 em을 사용하도록 되어 있다.
나머지 style, weight, family는 xml의 TextView와 동일하다고 봐주면 될 것 같다!
Text(
text = "Hello $name!",
fontSize = 12.sp,
fontStyle = FontStyle.Italic,
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.SansSerif
)
3. letterSpacing(자간), lineHeight (줄 간격)
letterSpacing과 lineHeight도 동일하게 TextUnit이 들어가야한다.
(sp 또는 em으로 값을 주어야 한다는 뜻!)
Text(
text = "Hello $name! \n 안녕하세요"
)
Text(
text = "Hello $name! \n 안녕하세요",
letterSpacing = 10.sp, // 자간 추가
)
Text(
text = "Hello $name! \n 안녕하세요",
letterSpacing = 10.sp,
lineHeight = 10.sp // 줄간격, 기본 값이 있고 지정시 지정된 값으로 변경
)
4. textDecoration, textAlign
textDecroation은 text에 underline을 넣거나 취소선을 넣는 등의 꾸미는 값이다.
textDecoration은 TextDecoration 값이 들어가야하고 아래와 같다.
@Stable
val None: TextDecoration = TextDecoration(0x0)
/**
* Draws a horizontal line below the text.
*
* @sample androidx.compose.ui.text.samples.TextDecorationUnderlineSample
*/
@Stable
val Underline: TextDecoration = TextDecoration(0x1)
/**
* Draws a horizontal line over the text.
*
* @sample androidx.compose.ui.text.samples.TextDecorationLineThroughSample
*/
@Stable
val LineThrough: TextDecoration = TextDecoration(0x2)
/**
* Creates a decoration that includes all the given decorations.
*
* @sample androidx.compose.ui.text.samples.TextDecorationCombinedSample
*
* @param decorations The decorations to be added
*/
fun combine(decorations: List<TextDecoration>): TextDecoration {
val mask = decorations.fastFold(0) { acc, decoration ->
acc or decoration.mask
}
return TextDecoration(mask)
}
Underline과 LineThrough는 기본적으로 제공하고 있고, combine도 제공하고 있는데 아래와 같이 사용하면 된다.
Text(
text = "Hello $name!",
textDecoration = TextDecoration.combine(
listOf(
TextDecoration.LineThrough,
TextDecoration.Underline
)
)
)
plus를 사용해서 아래와 같이 작성해도 똑같은 결과 값을 얻을 수 있다!
Text(
text = "Hello $name!",
textDecoration = TextDecoration.LineThrough
.plus(TextDecoration.Underline)
)
5. textAlign
textAlign은 text의 정렬을 말한다.
TextAlign의 값은 아래와 같다.
companion object {
val Left = TextAlign(1)
val Right = TextAlign(2)
val Center = TextAlign(3)
val Justify = TextAlign(4)
val Start = TextAlign(5)
val End = TextAlign(6)
fun values(): List<TextAlign> = listOf(Left, Right, Center, Justify, Start, End)
}
text를 센터 정렬 해보자!
Box(
modifier = Modifier.size(200.dp)
) {
Text(
text = "Hello $name!",
textAlign = TextAlign.Center
)
}
위와 같이 작성하면 어떻게 될까? 센터 정렬이 될까?
답은 당연히 X다!
textAlign은 text의 사이즈 안에서의 정렬이기 때문에 사이즈를 지정해주지 않으면 사이즈는 text에 딱맞게 되어있기 때문에 아무런 일이 일어나지 않는다.
Box(
modifier = Modifier.size(200.dp)
) {
Text(
text = "Hello $name!",
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxSize()
)
}
부모의 사이즈를 받아 위와같이 작성한다면 이제 가운데로 갈 수 있을까?
위의 코드를 돌려보면 아래와 같이 나오게 된다.
이와 같이 나오는 것을 예상했다면 바로 6번으로 가면 된다😁
정 가운데로 갈 것 같은데 가운데로 가지 않는다.
위로 올라가서 TextAlign 값을 보면 left, right, start, end, justify, center의 값을 가지고 있다.
각 값들을 보면 좌우와 가운데의 값만을 가지고 있다.
TextAlign은 가로 정렬의 값만을 가지고 있는 것이다!
TextAlign class에도 아래와 같이 적혀있다.
Defines how to align text horizontally.
정 가운데로 가기 위해서는 아래와 같이 할 수 있다.
Box(
modifier = Modifier.size(200.dp)
) {
Text(
text = "Hello $name!",
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
.align(Alignment.Center)
)
}
modifier에 align값을 주게 되면 생각하는 대로 값이 나올 것이다!
물론 TextAlign 값을 주지 않고 아래와 같이 값을 주어도 동일하게 동작한다😀
Box(
modifier = Modifier.size(200.dp)
) {
Text(
text = "Hello $name!",
textAlign = TextAlign.Center,
modifier = Modifier.align(Alignment.Center)
)
}
6. overflow, softWrap, maxLines
overflow는 text가 지정된 line 수나 길이에 넘쳤을 경우 어떻게 보이게 할 것인지에 대한 것이다.
TextOverflow를 사용해야하며 아래와 같이 3개가 있다.
companion object {
@Stable
val Clip = TextOverflow(1)
@Stable
val Ellipsis = TextOverflow(2)
@Stable
val Visible = TextOverflow(3)
}
위의 코드를 테스트하기 위해 최대 줄 수인 maxLine을 설정하여 아래와 같이 코드를 작성하여 테스트 해보았다.
Box(
modifier = Modifier.size(200.dp)
) {
Text(
text = "동해 물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려강산 대한 사람, 대한으로 길이 보전하세",
overflow = TextOverflow.Visible, // TextOverflow.Ellipsis, TextOverflow.Clip
maxLines = 2
)
}
Ellipsis는 뒤에 말줄임표가 나오게 된다.
Clip과 Visible은 동일하게 보이나 나올 수 있는 부분까지는 나온다는 공통점은 있지만,
Clip은 나올 수 있는 부분에서 글이 잘린다는 것이고 Visible은 안보이는 곳에서 글이 전체 다 보이고 있다는 차이점이 있다!
softWrap은 자동 줄바꿈이라고 보면 된다.
기본은 true인데 위의 코드에서 softWrap 을 false로 바꾸게 되면!?
Text(
text = "동해 물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려강산 대한 사람, 대한으로 길이 보전하세",
overflow = TextOverflow.Visible, // TextOverflow.Ellipsis, TextOverflow.Clip
maxLines = 2,
softWrap = false
)
maxLine을 2로 지정해도 줄바꿈이 되지 않아 1줄로 나오게 된다.
false일 경우 글자가 무제한 수평 공간이 있는 것처럼 배치되기 때문에 당연히 overflow에 값을 주어도 원하는 것처럼 나올 수 없게 될 수 있다.
7. onTextLayout
새로운 텍스트 레이아웃이 계산될 때 실행되는 콜백으로 TextLayoutResult를 제공한다.
TextLayoutResult 개체는 문단 정보, 텍스트 크기, 기준선 및 기타 세부 정보등을 제공한다.
class TextLayoutResult constructor(
val layoutInput: TextLayoutInput,
val multiParagraph: MultiParagraph,
val size: IntSize
) {
val firstBaseline: Float = multiParagraph.firstBaseline
val lastBaseline: Float = multiParagraph.lastBaseline
val didOverflowHeight: Boolean get() = multiParagraph.didExceedMaxLines ||
size.height < multiParagraph.height
val didOverflowWidth: Boolean get() = size.width < multiParagraph.width
val hasVisualOverflow: Boolean get() = didOverflowWidth || didOverflowHeight
val placeholderRects: List<Rect?> = multiParagraph.placeholderRects
val lineCount: Int get() = multiParagraph.lineCount
fun getLineStart(lineIndex: Int): Int = multiParagraph.getLineStart(lineIndex)
fun getLineEnd(lineIndex: Int, visibleEnd: Boolean = false): Int =
multiParagraph.getLineEnd(lineIndex, visibleEnd)
fun isLineEllipsized(lineIndex: Int): Boolean = multiParagraph.isLineEllipsized(lineIndex)
fun getLineTop(lineIndex: Int): Float = multiParagraph.getLineTop(lineIndex)
fun getLineBottom(lineIndex: Int): Float = multiParagraph.getLineBottom(lineIndex)
fun getLineLeft(lineIndex: Int): Float = multiParagraph.getLineLeft(lineIndex)
fun getLineRight(lineIndex: Int): Float = multiParagraph.getLineRight(lineIndex)
fun getLineForOffset(offset: Int): Int = multiParagraph.getLineForOffset(offset)
fun getLineForVerticalPosition(vertical: Float): Int =
multiParagraph.getLineForVerticalPosition(vertical)
fun getHorizontalPosition(offset: Int, usePrimaryDirection: Boolean): Float =
multiParagraph.getHorizontalPosition(offset, usePrimaryDirection)
fun getParagraphDirection(offset: Int): ResolvedTextDirection =
multiParagraph.getParagraphDirection(offset)
fun getBidiRunDirection(offset: Int): ResolvedTextDirection =
multiParagraph.getBidiRunDirection(offset)
fun getOffsetForPosition(position: Offset): Int =
multiParagraph.getOffsetForPosition(position)
fun getBoundingBox(offset: Int): Rect = multiParagraph.getBoundingBox(offset)
fun getWordBoundary(offset: Int): TextRange = multiParagraph.getWordBoundary(offset)
fun getCursorRect(offset: Int): Rect = multiParagraph.getCursorRect(offset)
fun getPathForRange(start: Int, end: Int): Path = multiParagraph.getPathForRange(start, end)
//...
}
TextLayout에는 위와 같이 여러 값과 기능들이 있다.
var backgroundColor by remember { mutableStateOf(Color.White) }
Text(
text = text,
onTextLayout = { result ->
backgroundColor =
if(result.lineCount >= 2 ) Color.Red else Color.White
},
modifier = Modifier.background(backgroundColor)
)
text의 line 수가 2개 이상일 때 배경이 빨간색으로 변하는 코드이다.
이렇게 값에 의해 배경 등 변경이 필요할 때 사용할 수 있다!
[출처 및 참고]
'개발 공부 > 안드로이드' 카테고리의 다른 글
[Compose] 컴포즈 공부하기 12 - BottomAppBar (1) | 2023.10.10 |
---|---|
[Compose] 컴포즈 공부하기 11 - TopAppBar (0) | 2023.10.04 |
[Compose] 컴포즈 공부하기 9 - TextField (0) | 2023.09.20 |
[Compose] 컴포즈 공부하기 8 - CheckBox (0) | 2023.09.13 |
[Compose] 컴포즈 공부하기 7 - Snackbar (0) | 2023.09.11 |