
새 프로젝트를 만들 때 xml 방식에서는 Empty Views Activity로 만들었지만 Compose는 Empty Activity로 만들어준다.

컴포즈로 프로젝트를 만들면 기존에 xml파일에 있던 디자인 미리보기가 kt파일에도 추가가 된다.

package kr.co.lion.jetpackcomposetest
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import kr.co.lion.jetpackcomposetest.ui.theme.JetPackComposeTestTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JetPackComposeTestTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
JetPackComposeTestTheme {
Greeting("Android")
}
}
@Composable : 눈에 보이는 UI요소를 구성할수 있다는 의미
setContent : Activity가 관리할 화면을 지정해준다.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Activity가 관리할 화면을 지정해준다.
setContent {
Text(text = "하하하하")
}
}
}

setContent 안에 작업할 내용을 @Composable함수로 만들어서 호출하면 된다.
눈에 보이는 요소 하나당 하나의 @Composable 함수를 만든다
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Activity가 관리할 화면을 지정해준다.
setContent {
MemoApp()
}
}
}
// @Composable : 화면 요소를 만들고 구성하기 위한 함수들에 붙여준다.
// 이 함수에서 만들어지는 화면 요소들은 실제로 화면상에 반영된다.
@Composable
fun MemoApp(modifier: Modifier = Modifier){
Text(text = "안녕하세요")
}
이 상태에서는 미리보기 화면이 나오지 않는다.

@Preview를 붙여주면 미리보기 화면이 나온다.
@Preview
@Composable
fun Preview(){
JetPackComposeTestTheme {
MemoApp()
}
}

미리보기는 개발 시 화면 테스트를 위해 사용한다.
@Composable
fun MemoApp(modifier: Modifier = Modifier){
Box {
Text(text = "안녕하세요")
Text(text = "반갑습니다")
}
}

@Composable
fun MemoApp(modifier: Modifier = Modifier){
Row {
Text(text = "안녕하세요")
Text(text = "반갑습니다")
}
}

@Composable
fun MemoApp(modifier: Modifier = Modifier){
Column {
Text(text = "안녕하세요")
Text(text = "반갑습니다")
}
}

@Composable
fun MemoApp(modifier: Modifier = Modifier){
Column(modifier = Modifier.padding(10.dp)) {
Text(text = "안녕하세요")
}
}

화면 회전이 발생했거나 다른 화면으로 갔다 왔거나 할 때 화면 요소들이 초기화되는 경우가 있다.
remember 프로퍼티에 저장된 값은 어떠한 일이 벌어지더라도 초기화 되지 않는다.
View에 지정하는 값을 저장하는 용도로 사용한다.
// 텍스트 필드
TextField(
// 텍스트 필드를 통해 보여줄 값이나 프로퍼티를 지정한다.
value = "안녕하세요",
onValueChange = {}
)
onValueChange 설정을 하지 않은 경우 텍스트 필드에 키보드를 눌러도 입력한 값이 텍스트필드에 출력되지 않는다. (입력한 값은 실제로 들어가 있다)

// remember 프로퍼티
// 화면 회전이 발생했거나 다른 화면으로 갔다 왔거나 할 때
// 화면 요소들이 초기화되는 경우가 있다.
// remember 프로퍼티에 저장된 값은 어떠한 일이 벌어지더라도 초기화 되지 않는다.
// View에 지정하는 값을 저장하는 용도로 사용한다.
val textFieldState = remember {
mutableStateOf("")
}
// 텍스트 필드
TextField(
// 텍스트 필드를 통해 보여줄 값이나 프로퍼티를 지정한다.
// remember 프로퍼티가 관리하는 값을 넣어주는 코드를 작성한다.
// 여기에 넣어주는 값이 화면상에 나타난다.
value = textFieldState.value,
// TextField의 입력값이 변경되는 동작하는 리스너
// TextField를 클릭하고 입력을 하면 실제로는 입력이 되지만
// 화면상에는 어떠한 변화가 이루어지지 않는다.
// 여기에서 value에 값을 넣어주는 작업을 해야 한다.
onValueChange = {textValue -> textFieldState.value = textValue}
)
이제는 입력한 내용이 화면에 반영된다.

remember 프로퍼티가 관리하는 값을 View의 value에 지정하는 구조, 입력한 값이 remember프로퍼티의 값으로 들어가는 구조가 이전에 배운 MVVM 패턴과 동일한 구조이다.
마찬가지로 나중에 입력한 값을 가져올 때에는 View에서 가져오는게 아니라 remember 프로퍼티의 값을 가져오면 된다.
remember 프로퍼티 ≒ MutableLiveData
remember 프로퍼티는 @Composable 안에서만 사용할 수 있다.
@Composable
fun MemoApp(modifier: Modifier = Modifier){
// 레이아웃
// Box : 중첩해서 배치한다.
// Row : 좌측에서 우측으로 배치한다.
// Column : 위에서 아래로 배치한다.
// padding : 내부의 여백
Column(
modifier = Modifier
// 내부의 여백
.padding(10.dp)
// 크기
// fillMaxWidth() : 가로 길이를 꽉 채운다.
// fillMaxHeight() : 세로 길이를 꽉 채운다.
// fillMaxSize() : 가로 세로 길이를 꽉 채운다.
.fillMaxSize())
{
// remember 프로퍼티
// 화면 회전이 발생했거나 다른 화면으로 갔다 왔거나 할 때
// 화면 요소들이 초기화 되는 경우가 있다.
// remember 프로퍼티에 저장된 값은 어떤한 일이 벌어지더라도 초기화 되지 않는다.
// View에 지정하는 값을 저장하는 용도로 사용한다.
val textFieldState = remember {
mutableStateOf("")
}
TextFieldFirst(textFieldState)
}
}
// 텍스트 필드 구성
@Composable
fun TextFieldFirst(textFieldState: MutableState<String>){
// 텍스트 필드
TextField(
// 텍스트 필드를 통해 보여줄 값이나 프로퍼티를 지정한다.
// remember 프로퍼티가 관리하는 값을 넣어주는 코드를 작성해준다.
// 여기에 넣어주는 값이 화면상에 나타난다.
value = textFieldState.value,
// TextField의 입력값이 변경되는 동작하는 리스너
// TextField를 클릭하고 입력을 하면 실제로는 입력이 되지만
// 화면상에는 어떠한 변화가 이루어지지 않는다.
// 여기에서 value 에 값을 넣어주는 작을 해야 한다.
onValueChange = {textValue -> textFieldState.value = textValue},
modifier = Modifier.fillMaxWidth())
}
// 버튼
@Composable
fun ButtonTest(){
Button(
onClick = { /*TODO*/ },
modifier = Modifier.fillMaxWidth()
) {
Text(text = "버튼입니다.")
}
}

View 사이에 여백을 줄 때 Spacer를 사용한다.
TextFieldFirst(textFieldState)
// 여백
Spacer(modifier = Modifier.padding(top = 10.dp))
ButtonTest()

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Activity가 관리할 화면을 지정해준다.
setContent {
JetPackComposeTestTheme {
MemoApp()
}
}
}
}
// @Composable : 화면 요소를 만들고 구성하기 위한 함수들에 붙혀준다.
// 이 함수에서 만들어는 화면 요소들은 실제로 화면상에 반영된다.
@Composable
fun MemoApp(modifier: Modifier = Modifier){
// 레이아웃
// Box : 중첩해서 배치한다.
// Row : 좌측에서 우측으로 배치한다.
// Column : 위에서 아래로 배치한다.
// padding : 내부의 여백
Column(
modifier = Modifier
// 내부의 여백
.padding(10.dp)
// 크기
// fillMaxWidth() : 가로 길이를 꽉 채운다.
// fillMaxHeight() : 세로 길이를 꽉 채운다.
// fillMaxSize() : 가로 세로 길이를 꽉 채운다.
.fillMaxSize())
{
// remember 프로퍼티
// 화면 회전이 발생했거나 다른 화면으로 갔다 왔거나 할 때
// 화면 요소들이 초기화 되는 경우가 있다.
// remember 프로퍼티에 저장된 값은 어떤한 일이 벌어지더라도 초기화 되지 않는다.
// View에 지정하는 값을 저장하는 용도로 사용한다.
val textFieldState = remember {
mutableStateOf("")
}
val resultState = remember {
mutableStateOf("")
}
TextFieldFirst(textFieldState)
// 여백
Spacer(modifier = Modifier.padding(top = 10.dp))
ButtonTest(textFieldState, resultState)
Spacer(modifier = Modifier.padding(top = 10.dp))
TextResult(resultState)
}
}
// 텍스트 필드 구성
@Composable
fun TextFieldFirst(textFieldState: MutableState<String>){
// 텍스트 필드
TextField(
// 텍스트 필드를 통해 보여줄 값이나 프로퍼티를 지정한다.
// remember 프로퍼티가 관리하는 값을 넣어주는 코드를 작성해준다.
// 여기에 넣어주는 값이 화면상에 나타난다.
value = textFieldState.value,
// TextField의 입력값이 변경되는 동작하는 리스너
// TextField를 클릭하고 입력을 하면 실제로는 입력이 되지만
// 화면상에는 어떠한 변화가 이루어지지 않는다.
// 여기에서 value 에 값을 넣어주는 작을 해야 한다.
onValueChange = {textValue -> textFieldState.value = textValue},
modifier = Modifier.fillMaxWidth())
}
// 버튼
@Composable
fun ButtonTest(textFieldState: MutableState<String>, resultState: MutableState<String>){
Button(
// 버튼을 눌렀을 때 동작하는 리스너
onClick = {
// 텍스트 필드와 연결되어 있는 remember 프로퍼티의 값을
// 텍스트와 연결되어 있는 remember 프로퍼티에 담아준다.
resultState.value = textFieldState.value
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "버튼입니다.")
}
}
// 결과
@Composable
fun TextResult(resultState:MutableState<String>){
Text(text = resultState.value)
}


