텍스트 속성 정리 -- (1)

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {

    var lineCount = 0
    var hasVisualOverflow = false
    var sizeWidth = 0
    var sizeHeight = 0
    var lineStartIndex = 0

    Text(
        text = "Hello $name!",                      //텍스트에 들어갈 내용
        fontSize = 60.sp,                           //텍스트 사이즈
        lineHeight = 60.sp,                         //텍스트 라인 높이
        color = Color.Black,                        //텍스트 색상
        textAlign = TextAlign.Center,               //텍스트 정렬
        fontFamily = FontFamily.Serif,              //텍스트 폰트 지정
        letterSpacing = 2.sp,                       //글자간 간격
        overflow = TextOverflow.Ellipsis,           //영역 초과시 말줄임(..)처리
        textDecoration = TextDecoration.Underline,  //텍스트 밑줄 처리
        softWrap = true,                            //줄바꿈 허용
        modifier = modifier                         //modifier객체
            .fillMaxWidth()                         //width를 화면 가득 채움
            .wrapContentHeight()                    //height를 내용만큼만 채움
            .padding(10.dp, 0.dp, 10.dp, 0.dp),     //텍스트 바깥 여백 설정 (Left, Top, Right, Bottom)
        onTextLayout = { result ->                  //텍스트가 그려진 후 호출되는 콜백
            lineCount = result.lineCount            //텍스트가 몇줄로 표시됐는지 리턴
            hasVisualOverflow = result.hasVisualOverflow    //텍스트가 잘렸는지 여부를 리턴 (...이 표시되는 경우 true)
            sizeWidth = result.size.width           //텍스트 width
            sizeHeight = result.size.height         //텍스트 height
            Log.d("onTextLayout","lineCount: ${lineCount}")
            Log.d("onTextLayout","hasVisualOverflow: ${hasVisualOverflow}")
            Log.d("onTextLayout","sizeWidth: ${sizeWidth}")
            Log.d("onTextLayout","sizeHeight: ${sizeHeight}")
        }
    )

onTextLayout -> 로그를 찍어보면 두번 호출되는것을 확인 할 수 있다. 

초기 레이아웃 예측 시 호출 -> 레이아웃 완료 후 호출 총 두번 호출 된다. 

텍스트가 다 그려진 후에 더보기 버튼이나 접기 버튼이 노출되어야 하는 상황이라면 onTextLayout안에서 노출을 시키면 될 듯 한데 동일한 코드가 두번 호출된다는게 비효율적인게 아닌가 싶다... 할거면 다 그려진 다음 한번만 호출하지 왜 두번호출되게 했을까?

두번 호출 하는 이유 

- 한 번만 호출하는 경우 예측이 틀린 경우 레이아웃 깨짐이나 재조정이 발생 할 가능성이 있음

- 두 번 호출함으로써 초기 렌더링 지연을 줄이고 렌더링 이후 정확한 상태 업데이트를 보장함

 

두번 째 호출에서 UI변경사항을 처리하고 싶은 경우에는
상태 플래그 변수를 저장해서 사용하는 방법과 LaunchedEffect를 사용하는 방법이 있는데 해당 방법은 천천히 알아보도록 하자


텍스트 위치 조정하기 -- (2)


화면 전체 가운데 정렬을 위해 Box를 추가하고 Alignment.Center값을 추가해주면 된다.

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {

    Box(modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Hello $name!",                      //텍스트에 들어갈 내용
            fontSize = 20.sp,                           //텍스트 사이즈
            color = Color.Black,                        //텍스트 색상
        )
    }
}

contentAlignment --> Alignment.CenterStart, Center, BottomCenter 등 속성값을 통해 텍스트의 위치를 제어할 수 있다.

 

안드로이드 앱 화면을 그리는 방법

(1) Xml - ConstarintLayout, LinearLayout, RecyclerView등으로 화면을 그리는게 가능

(2) Compose - 선언형 UI로 새롭게 출시된 뷰를 그리는 방법이다. (2021년 7월 정식 버전 출시)

 

@Composable이란 Annotation을 붙여야만 화면에 그려지는 듯 하다.

그러면 여기서 궁금한게 Compose와 관련된 Annotation은 어떤것들이 있을까?

 

Annotation 종류

@Composable -> 실제 UI를 그리는 함수

@Preview(showBackground = true) -> 미리보기(배경 색 설정) -> 실제 화면에 그려지지 않음(테스트 용도로만 사용)

@Stable ->  값이 자주 바뀌지 않는 안정적인 클래스나 객체라는 것을 컴파일러에게 알려줌

@Immutable -> 변경이 불가능한 DataClass라는 것을 나타냄

@ReadOnlyComposable -> 상태를 변경하지 않고 읽기만 가능한 Composable 함수

 

Compose의 SampleActivity를 하나 만들 면 다음과 같은 코드를 볼 수 있는데 한줄 한줄 해석해 보자 

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            ComposeApplicationTheme {
                Scaffold( modifier = Modifier.fillMaxSize() ) { innerPadding ->
                    Greeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeApplicationTheme {
        Greeting("Android")
    }
}

 

1) ComposeApplicationTheme 

적용할 테마를 설정하는 함수

 

2) Scaffold (modifier)

기본적인 레이아웃 틀을 만들어주는 함수

Modifier.fillMaxSize() -> 화면 전체 크기만큼 차지하라는 의미

modifier

  -> Compose에서 컴포넌트의 속성값을 체이닝 형식으로 지정가능하게 해주는 객체

  xml에서는 뷰마다 속성값을 다 넣어주었지만 compose에서는 modifier로 공통 속성값들을 정의해서 재사용 가능하게 만들었다.
  체이닝 형식으로 사용 (**체이닝 순서에 따라 결과값이 다르기 때문에 주의해서 사용)

  크기나 위치 조절, 배경 등 설정들 지정 가능 

modifier = Modifier.padding(30.dp)
    .background(Color.White)
    .clickable{print("clicked")}

Nested(중첩된) ScrollView는 스크롤 뷰 안에 스크롤뷰 기능이 있는 뷰(RecyclerView)가 있는 경우 스크롤을 자연스럽게 해준다.
ScrollView안에 RecyclerView를 넣는 경우 스크롤이 충돌할 가능성이 있고 중첩스크롤을 지원하지 않는다.

하지만 NestedScrollView안에 길이가 긴 RecyclerView가 있는 경우 성능 저하가 발생할 수 있다.

NestedScrollView는 모든 아이템을 한번에 측정하고 렌더링하려고 하기 때문에 리스트가 길수록 속도가 느려진다.

RecyclerView의 사용 이점이 사라짐 (뷰 재사용)

 

재사용 되는 뷰가 많거나 리스트가 긴 경우 -> RecyclerView 사용

스크롤 되는 영역이 1개이고 재사용 되는 뷰가 없는 경우 -> ScrollView 사용

스크롤 되는 영역이 2개 이상이고 뷰 재사용이 중요하지 않거나 리스트가 짧은 경우 -> NestedScrollView

 

- 권한 추가 (zsh: permission denied: ./gradlew 권한이 없는 경우 사용)

chmod +x ./gradlew

 

- 전체 리빌드

./graldew clean build

 

- 특정 모듈만 리빌드

./gradlew :module_name:clean :module_name:build

 

- 클린 프로젝트

./gradlew clean

 

권한 추가 후 다음과 같은 오류 발생(env: bash\r: No such file or directory)시 입력

sed -i '' $'s/\r//' gradlew --> (gradlew의 CRLF줄바꿈을 LF로 변경)

+ Recent posts