From_Base

[Jetpack Compose] Chapter7. Text 개념 & 활용 실습 본문

Android/Jetpack Compose

[Jetpack Compose] Chapter7. Text 개념 & 활용 실습

base_coding 2025. 1. 14. 05:00

개요:

이번 챕터에서는 Jetpack Compose의 핵심 컴포저블 중 하나인 Text에 대해 자세히 알아보겠습니다.

 

Text 컴포저블은 화면에 텍스트를 표시하는 데 사용되며, Android의 XML 레이아웃에서 TextView와 유사한 역할을 합니다.

Jetpack Compose의 Text는 다양한 스타일링 옵션과 유연한 텍스트 처리 기능을 제공해주기 때문에, 사용자 인터페이스에 풍부한 텍스트 표현을 가능하게 해줍니다.

 


Text의 기본 사용법:

Text 컴포저블은 가장 간단하게 문자열 리소스 또는 직접 입력한 텍스트를 화면에 표시합니다.

Text(text = "안녕하세요, Jetpack Compose!")
Text(text = stringResource(id = R.string.string_name)) 
// 위 코드는 리소스 폴더 (res) 안에 있는 strings.xml 파일에서
// string_name이라는 ID를 가진 문자열을 가져와서 Text 컴포저블에 표시하는 코드
// stringResource(): ID를 이용하여 문자열 리소스 값을 가져오는 함수

// 이렇게 코드를 작성하면 앱의 이름을 하드코딩하는 대신
// strings.xml 파일에 정의하여 관리할 수 있어서 편리하고 유지보수도 좋음

 

 

또한, Text 컴포저블은 Modifier를 비롯한 매개변수들을 사용하여 다양한 스타일과 레이아웃 속성을 적용할 수 있습니다.

예를 들어, 텍스트의 색상, 글꼴, 크기, 정렬 등을 변경할 수 있습니다.

Text(
    text = "Hello, Compose!",
    modifier = Modifier
        .background(Color.Yellow)
        .padding(16.dp)
        .fillMaxWidth(),
    color = Color.Blue,
    fontSize = 20.sp,
    fontWeight = FontWeight.Bold,
    textAlign = TextAlign.Center
)

 


Text의 스타일링 ( TextStyle ):

Text 컴포저블은 TextStyle을 사용하여 텍스트의 스타일을 세밀하게 제어할 수 있습니다.

TextStyle은 텍스트의 색상, 글꼴, 크기, 정렬, 줄 간격 등 다양한 속성을 포함합니다.

 

 

🔳 TextStyle의 주요 속성

  • color: 텍스트의 색상을 지정합니다.
  • fontFamily: 텍스트의 글꼴을 지정합니다.
  • fontSize: 텍스트의 크기를 지정합니다. (sp 단위)
  • fontWeight: 텍스트의 굵기를 지정합니다. (예: FontWeight.Bold, FontWeight.Normal)
  • fontStyle: 텍스트의 스타일을 지정합니다. (예: FontStyle.Italic)
  • textAlign: 텍스트의 정렬을 지정합니다. (예: TextAlign.Start, TextAlign.Center, TextAlign.End, TextAlign.Justify)
  • textDecoration: 텍스트에 밑줄, 취소선 등의 장식을 추가합니다. (예: TextDecoration.Underline, TextDecoration.LineThrough)
  • lineHeight: 텍스트의 줄 간격을 지정합니다. (sp 단위)
  • maxLines: 텍스트의 최대 줄 수를 지정합니다.
  • overflow: 텍스트가 지정된 영역을 넘어갈 경우 어떻게 처리할지 지정합니다. (예: TextOverflow.Ellipsis)

 


🔳 AnnotatedString  buildAnnotatedString withStyle SpanStyle

( 텍스트에 부분적으로 개별 스타일 적용해보기 )

 

 

AnnotatedString을 사용하면 텍스트의 일부분에만 다른 스타일을 적용할 수 있습니다.

buildAnnotatedString 빌더 함수를 사용하여 AnnotatedString을 생성하고, withStyle 함수를 사용하여 특정 범위의 텍스트에 SpanStyle을 적용함으로써 텍스트에 부분적으로 개별 스타일을 적용해볼 수 있습니다. 

 

AnnotatedString은 Jetpack Compose에서 텍스트의 일부분에만 다양한 스타일을 적용할 수 있도록 해주는 강력한 도구입니다.

 

AnnotatedString을 사용하면 텍스트의 특정 단어, 구절, 또는 문장에 각기 다른 색상, 폰트, 크기, 장식 등을 적용하여 풍부한 텍스트 표현을 만들어낼 수 있습니다.

 

 

 

 

buildAnnotatedString, withStyle, SpanStyle의 역할 분담:

  • buildAnnotatedString: AnnotatedString이라는 캔버스를 생성하는 빌더 함수입니다. 이 함수 안에서 append를 통해 일반 텍스트를 추가하거나, withStyle을 통해 특정 부분에 스타일을 적용할 수 있습니다.

 

  • withStyle: buildAnnotatedString 내에서 사용되는 함수로, 특정 범위의 텍스트에 스타일을 적용합니다. SpanStyle을 인자로 받아 해당 스타일을 적용할 텍스트 범위를 지정합니다.
    • withStyle의 첫 번째 인자로 SpanStyle 객체를 전달합니다.
    • withStyle의 두 번째 인자로 스타일을 적용할 텍스트를 추가하는 람다 함수를 전달합니다. 람다 함수 내에서 append 함수를 사용하여 텍스트를 추가합니다.
    • withStyle은 buildAnnotatedString에게 어떤 부분에 어떤 스타일을 적용해야 하는지 알려주는 역할을 합니다.

 

  • SpanStyle: 텍스트의 일부분에 적용될 스타일을 정의하는 클래스입니다. color, fontWeight, fontFamily, textDecoration 등 TextStyle에서 제공하는 대부분의 스타일 속성을 사용할 수 있습니다.

 

 

 

동작 과정:

  1. buildAnnotatedString 함수를 사용하여 AnnotatedString 객체를 생성합니다.
  2. append 함수를 사용하여 일반 텍스트를 빌더에 차곡차곡 추가합니다.
  3. withStyle 함수를 사용하여 특정 범위의 텍스트에 SpanStyle을 적용합니다.
    • 바로 이 withStyle 함수 내에서 append 함수를 사용하여 withStyle에서 지정한 스타일을 적용할 텍스트를 추가하는 것.
  4. buildAnnotatedString 함수는 append와 withStyle에서 추가된 텍스트와 스타일 정보를 바탕으로 최종 AnnotatedString 객체를 생성합니다.

 

예제 코드:

Text(
    text = buildAnnotatedString {
        append("This is ") // 일반 텍스트 추가
        withStyle(style = SpanStyle(color = Color.Red, fontWeight = FontWeight.Bold)) { // 빨간색, 굵은 글씨 스타일 적용 시작
            append("Red") // "Red" 텍스트에 스타일 적용
        } // 스타일 적용 끝
        append(" and ") // 일반 텍스트 추가
        withStyle(style = SpanStyle(color = Color.Blue, textDecoration = TextDecoration.Underline)) { // 파란색, 밑줄 스타일 적용 시작
            append("Blue") // "Blue" 텍스트에 스타일 적용
        } // 스타일 적용 끝
        append(" text.") // 일반 텍스트 추가
    }
)

 

 

 

 


 

 실습: Text 컴포저블을 활용한 텍스트 표시 및 다양한 텍스트 스타일 지정해보기 

 

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //enableEdgeToEdge()
        setContent {
            Chapter7Theme {
                TextContainer()
            }
        }
    }
}

@Composable
fun TextContainer() {
    val name = "WjLee"
    val words = stringResource(R.string.dummy_short_test)
    var wordArray = words.split(" ")

    // 텍스트 목록을 저장할 상태 변수
    val textList = remember { mutableStateListOf<String>() }

    // Random 색상을 remember로 기억 (클릭텍스트로 인해 재렌더링 일어나더라도 기존 색상이 유지되도록 Color 객체를 기억해두기.)
    val randomColors = remember {
        // map 함수는 컬렉션(예: 배열, 리스트)의 각 요소에 특정 연산(transform람다 내부에 기술)을 적용하여 새로운 컬렉션을 생성하는 함수
        // 여기서는,map 함수을 사용하여 wordArray의 length만큼 순환하면서 Color 객체를 생성하고, 이를 randomColors에 저장
        wordArray.map {
            Color(Random.nextInt(0, 255), Random.nextInt(0, 255), Random.nextInt(0, 255))
        }
    }
    // rememberScrollState: 스크롤 상태를 기억하는 함수. 스크롤 위치를 저장하고, 스크롤 위치를 변경할 때마다 스크롤 상태를 업데이트.
    val scrollState = rememberScrollState()

    Column(
        verticalArrangement = Arrangement.spacedBy(10.dp),
        modifier = Modifier
            .padding(16.dp)
            .fillMaxSize()
            .verticalScroll(scrollState)
    ) {

        Text(
            // buildAnnotatedString: AnnotatedString을 생성하는 빌더 함수. buildAnnotatedString를 사용하면 텍스트의 각 부분에 원하는 스타일을 자유롭게 적용할 수 있음.
            // AnnotatedString: 텍스트의 일부분에 각기 다른 스타일(색상, 폰트, 크기 등)을 적용할 수 있게 해주는 클래스.
            // withStyle: buildAnnotatedString 안에서 특정 텍스트 범위에 스타일을 적용할 때 사용하는 함수.
            // spanStyle: 텍스트의 스타일을 지정하는 클래스. 색상, 글꼴, 크기 등을 지정할 수 있음.

            // withStyle을 사용하여 스타일을 지정하고(SpanStyle을 통해) -> withStyle의 람다 함수 내부에 append를 사용하여 텍스트를 추가하면 -> append 함수로 추가된 텍스트에는 withStyle에서 지정한 스타일이 적용됨.
            // buildAnnotatedString는 이 정보들을 바탕으로 최종적으로 AnnotatedString을 생성

            text = buildAnnotatedString {

                // Brush.linearGradient: 선형 그라데이션을 생성하는 함수. 여러 색상을 지정하면 그 색상들을 선형으로 연결한 그라데이션을 생성.
                withStyle(
                    style = SpanStyle(
                        brush = Brush.linearGradient(
                            listOf(
                                Color.Red,
                                Color(255, 165, 0),
                                Color.Green,
                                Color.Blue,
                                Color(75, 0, 130),
                                Color(238, 130, 238)
                            )
                        )
                    )
                ) {
                    append("안녕하세요? 반갑습니다!\n")
                }
                withStyle(style = SpanStyle(color = Color.Blue, fontWeight = FontWeight.Bold))
                {
                    append("오늘도 좋은하루되세요!\n")
                }

                withStyle(
                    style = SpanStyle(
                        color = Color.Green,
                        fontFamily = FontFamily(Font(R.font.bamin_pro))
                    )
                )
                {
                    append("감사합니다~!")
                }
            },

            modifier = Modifier
                .fillMaxWidth()
                .background(Color(0xFFF5ECEC)),

            style = TextStyle(
                textAlign = TextAlign.Start,
            ),

            fontSize = 20.sp,
            lineHeight = 30.sp
        )

        Text(
            text = "안녕하세요? 반갑습니다! ${name}",
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Yellow),
            style = TextStyle(
                textAlign = TextAlign.Center,
            ),
            fontWeight = FontWeight.Bold,
            fontSize = 20.sp,
        )

        Text(
            text = stringResource(id = R.string.dummy_short_test),
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Yellow),
            style = TextStyle(
                //Justify: 텍스트를 양쪽 맞춤으로 정렬
                textAlign = TextAlign.Justify,
                // 데코레이션: 밑줄, 취소선 등 텍스트에 추가적인 장식을 부여
                // combine: 여러 데코레이션을 리스트로 받아서 결합
                textDecoration = TextDecoration.combine(
                    listOf(
                        TextDecoration.LineThrough,
                        TextDecoration.Underline
                    )
                ),
            )
        )

        Text(
            text = buildAnnotatedString {
                wordArray.forEachIndexed { index, word ->
                    withStyle(
                        style = SpanStyle(
                            fontWeight = FontWeight.Bold,
                            color = randomColors[index]
                        )
                    ) {
                        append("${word} ")
                    }
                }
            }
        )

        Text(
            text = stringResource(id = R.string.dummy_short_test),
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Yellow),
            style = TextStyle(
                textAlign = TextAlign.Start,
                // fontFamily: 텍스트의 글꼴을 지정, 여기서는 배달의 민족 꾸부림체 사용.
                fontFamily = FontFamily(Font(R.font.bamin_ggu)),
            ),
            fontSize = 18.sp,
            // lineHeight: 텍스트의 줄 간격을 지정
            lineHeight = 30.sp
        )

        Text(
            text = stringResource(id = R.string.dummy_long_test),
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Yellow),
            style = TextStyle(
                textAlign = TextAlign.Start,
            ),
            // maxLines: 텍스트의 최대 행 수를 지정
            maxLines = 3,
            // overflow: 텍스트가 표시 영역을 벗어났을 때 처리 방법을 지정.
            // Ellipsis: 텍스트가 표시 영역을 벗어났을 때 생략 부호(...)를 표시
            overflow = TextOverflow.Ellipsis
        )

        ClickableText(
            text = AnnotatedString("클릭!"), onClick = {
                textList.add("클릭되었습니다~")
            }, style = TextStyle(
                color = Color.Blue,
                fontSize = 20.sp
            )
        )

        // 텍스트 목록을 표시
        textList.forEach { text ->
            Text(text = text, modifier = Modifier.padding(10.dp))
        }

    }
}


@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    Chapter7Theme {
        TextContainer()
    }
}

 

 

 

 

  결과 화면  

 

 

 

 

 

📢 res 디렉터리에 다운로드받은 폰트 추가해주기!

리소스 디렉터리에 font 하부 디렉터리 추가 & 사용할 .ttf 폰트파일들 넣어주기

 

 

 

 

 


 

 

참고 자료:

https://youtu.be/rZ5k-b3xmkU?si=p5wwIOxM2s8sOLPz

https://developer.android.com/develop/ui/compose/text?hl=ko

 

폰트 사이트: 

https://www.woowahan.com/fonts

 

우아한형제들

문 앞으로 일상의 행복을 배달합니다.

www.woowahan.com