[Android] Jetpack Compose - 시작하기, UI 구성하기, 버튼 상태 받아오기

알린·2024년 2월 21일
0

Android

목록 보기
8/21

Jetpack Compose

  • UI 개발을 간소화하기 위해 설계
  • 선언적인 접근방식으로, 데이터를 UI 계층 구조로 변환하는 일련의 함수를 호출해 UI를 설명
  • 데이터가 변경되면 함수를 자동으로 다시 실행해 UI 계층 구조를 업데이트
  • @Composable:구성 가능한 함수(컴포저블) 표시

Compose로 프로젝트 시작하기

  1. 새 프로젝트 만들기에서 [Empty Activity] 선택

  2. MainActivity에 다음과 같은 코드 자동 생성되어있음

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {  // 레이아웃 정의
            JetpackCompose_StudyTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Android")
                }
            }
        }
    }
}

// 구성 가능한 함수: 함수가 내부에서 다른 @Composable 함수 호출 가능
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(  // 지정된 입력 표시 함수
        text = "Hello $name!",
        modifier = modifier
    )
}

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

UI 조정

위 코드 빌드 시 다음과 같은 UI가 생성된다.

여기서 Hello Android!에 배경색을 넣어보려면,
Surface를 사용하면 된다.

💡 Surfase 및 MaterialTheme

  • Material Design과 관련된 개념
    • Material Design:사용자 인터페이스와 환경을 만드는 데 도움을 주기 위해 Google에서 만든 디자인 시스템
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(color = MaterialTheme.colorScheme.primary) {  // Greeting에 배경색 설정
        Text(  // 지정된 입력 표시 함수
            text = "Hello $name!",
            modifier = modifier
        )
    }
}

위의 코드에서는 글자의 배경색만 바꾸었지, 글자의 색상까지 바꿔주진 않았다.
이처럼, Compose Material 구성요소는 앱에 넣고자 하는 공통 기능(예: 텍스트에 적절한 색상 선택)을 처리하여 더 나은 환경을 만들도록 빌드된다.

수정자

  • 대부분의 Compose UI 요소는 modifier 매개변수를 선택적으로 허용
  • 수정자의 역할
    • 상위 요소 레이아웃 내에서 UI 요소가 배치되고 표시되고 동작하는 방식을 UI 요소에 알려줌
  • 정렬, 애니메이션 처리, 배치, 클릭 가능 여부 또는 스크롤 가능 여부 지정, 변환 등에서 사용
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(color = MaterialTheme.colorScheme.primary) {
        Text(
            text = "Hello $name!",
            modifier = modifier.padding(24.dp)  // 패딩 수정자 생성
        )
    }
}

컴포저블 재사용

  • UI를 구성하는 요소들이 많아질수록 중첩이 많이 일어나 코드의 가독성이 안좋아지는 것을 해결하기 위함
  • 재사용할 수 있는 작은 구성요소들을 만들어, 각 요소가 화면의 작은 부분을 담당하며 독립적으로 수정할 수 있도록 만듦
  • 함수는 기본적으로 빈 수정자가 할당되는 수정자 매개변수를 포함하는 것이 좋음

다음 코드 추가

@Composable
fun MyApp(modifier: Modifier = Modifier) {  // 빈 수정자가 할당되는 수정자 매개변수를 포함
    Surface(modifier = modifier, color = MaterialTheme.colorScheme.background) {
        Greeting("Android")
    }
}

MyApp 컴포저블을 재사용하여 코드 중복을 피할 수 있으므로 onCreate 콜백과 미리보기를 정리할 수 있다.


전체 코드

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {  // 레이아웃 정의
            JetpackCompose_StudyTheme {
                MyApp(modifier = Modifier.fillMaxSize())
            }
        }
    }
}

@Composable
fun MyApp(modifier: Modifier = Modifier) {  // 빈 수정자가 할당되는 수정자 매개변수를 포함
    Surface(modifier = modifier, color = MaterialTheme.colorScheme.background) {
        Greeting("Android")
    }
}

// 구성 가능한 함수: 함수가 내부에서 다른 @Composable 함수 호출 가능
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(color = MaterialTheme.colorScheme.primary) {
        Text(
            text = "Hello $name!",
            modifier = modifier.padding(24.dp)  // 패딩 수정자 생성
        )
    }
}

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

열과 행 만들기

  • Compose의 세 가지 기본 구성 요소: Column, Row, Box

Column을 사용해 요소들을 세로로 배치하는 코드

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(color = MaterialTheme.colorScheme.primary) {
        Column(modifier = modifier.padding(24.dp)) {
            Text(text = "Hello")
            Text(text = "$name")
        }
    }
}

  • 컴포저블 내에서 반복문 사용 가능
@Composable
fun MyApp(
    modifier: Modifier = Modifier,  // 빈 수정자가 할당되는 수정자 매개변수를 포함
    names: List<String> = listOf("World", "Compose")
) {
    Column(modifier) {
        for (name in names) {
            Greeting(name = name)
        }
    }
}

  • 일반 핸드폰 너비인 320dp로 프리뷰 설정
@Preview(showBackground = true, widthDp = 320)
  • 구성요소 가장 위, 아래 패딩 설정
@Composable
fun MyApp(
    modifier: Modifier = Modifier,  // 빈 수정자가 할당되는 수정자 매개변수를 포함
    names: List<String> = listOf("World", "Compose")
) {
    Column(modifier = modifier.padding(vertical = 4.dp)) {
        for (name in names) {
            Greeting(name = name)
        }
    }
}
  • 각 구성요소별 패딩 설정
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(
        color = MaterialTheme.colorScheme.primary,
        modifier = modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Column(modifier = modifier.fillMaxWidth().padding(24.dp)) {
            Text(text = "Hello")
            Text(text = name)
        }
    }
}

버튼 추가

  • Button, ElevatedButton, FilledTonalButton, OutlinedButton, TextButton 등 사용 가능
  • weight 수정자
    • 요소를 유연하게 만들기 위해 가중치가 없는 다른 요소(유연성 부족이라고 함)를 효과적으로 밀어내어 요소의 사용 가능한 모든 공간을 채움
    • fillMaxWidth와 중복됨
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Surface(
        color = MaterialTheme.colorScheme.primary,
        modifier = modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Row(modifier = Modifier.padding(24.dp)) {
            Column(modifier = Modifier.weight(1f)) {
                Text(text = "Hello")
                Text(text = name)
            }
            ElevatedButton(onClick = { /*TODO*/ }) {
                Text(text = "Show more")
            }
        }
    }
}

상태 받아오기

💡 리컴포지션

  • Compose 앱
    • 구성 가능한 함수를 호출하여 데이터를 UI로 변환함
  • 컴포지션
    • 데이터가 변경되면 Compose가 새 데이터로 함수를 다시 실행하여 업데이트된 UI를 만드는 것
    • Compose는 데이터가 변경된 구성요소만 다시 구성하고,
      영향을 받지 않는 구성요소는 다시 구성하지 않고 건너뛰도록 개별 컴포저블에서 필요한 데이터를 확인함
  • 컴포저블에 내부 상태를 추가하려면 mutableStateOf 함수를 사용

    💡 mutableStateOf
    어떤 값을 보유하고 그 값이 변경될 때마다 UI 업데이트(리컴포지션)를 트리거하는 인터페이스

  • 여러 리컴포지션 간에 상태를 유지하려면 remember를 사용하여 변경 가능한 상태를 기억

    💡 remember
    리컴포지션을 방지하는 데 사용되므로 상태가 재설정되지 않음

@Composable
fun Greeting(...) {
    val expanded = remember { mutableStateOf(false) }
    // ...
    ElevatedButton(
    	onClick = { expanded.value = !expanded.value },
	) {
   		Text(if (expanded.value) "Show less" else "Show more")
	}
}

프리뷰 확인하기

  1. 프리뷰 모드를 대화형 모드로 바꾸기
  2. 버튼을 눌렀을 때 less와 more로 잘 바뀌는지 확인

상태 받아와 반응하기

  • extraPadding에서 expanded 값이 true면 padding값을 넓혀주는 방법으로 구현
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    val expanded = remember { mutableStateOf(false) }
    val extraPadding = if (expanded.value) 48.dp else 0.dp
    Surface(
        color = MaterialTheme.colorScheme.primary,
        modifier = modifier.padding(vertical = 4.dp, horizontal = 8.dp)
    ) {
        Row(modifier = Modifier.padding(24.dp)) {
            Column(modifier = Modifier
                .weight(1f)
                .padding(bottom = extraPadding)
            ) {
                Text(text = "Hello")
                Text(text = name)
            }
            ElevatedButton(
                onClick = { expanded.value = !expanded.value },
            ) {
                Text(if (expanded.value) "Show less" else "Show more")
            }
        }
    }
}

profile
Android 짱이 되고싶은 개발 기록 (+ ios도 조금씩,,👩🏻‍💻)

0개의 댓글