CardView와 동일한 기능을 하는 Card
// CardView와 동일한 기능
Card(
modifier = Modifier
.fillMaxWidth(0.5f)
.padding(16.dp), // fraction으로 비율 지정 : 절반
shape = RoundedCornerShape(8.dp), // 모서리 둥글게
elevation = 5.dp,
) {
Box(
modifier = Modifier.height(200.dp)
) {
// Image 소스를 가져올 때는 painter 사용
Image(
painter = painterResource(id = R.drawable.umc),
contentDescription = "설명 : 인생네컷",
contentScale = ContentScale.Crop,
)
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopEnd,
) {
IconButton(onClick = {
isFavorite = !isFavorite
}) {
Icon(
imageVector = if (isFavorite) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
contentDescription = "favorite",
tint = Color.White,
)
}
}
}
}
Image 소스를 drawable에서 직접 가져올 경우
painter를 사용한다
이미지 위에 겹쳐있는 하트 아이콘 생성 → 새로운 Box 만들기
아이콘의 상태를 기억해주고 변화시켜주기 위해 아이콘 상태 저장 변수를 따로 지정
@Composable
fun ImageCard() {
// Icon 상태를 기억해줄 변수 - 컴포즈에서는 Boolean이 아닌 State 사용
// value 값을 자동으로 가져오도록 getValue, setValue import
// 자동 임포트가 안되므로 직접 해야함 -> by 사용 가능
var isFavorite by rememberSaveable {
mutableStateOf(false)
}
remomberSaveable → 화면 회전시 아이콘 상태값 변화하는 상황 방지
var isFavorite = remember {} 도 가능하지만, value를 항상 명시해주어야 하는 귀찮음 발생
→ by를 사용한다 ! 그러기 위해서는 getValue, setValue 직접 임포트하기
by를 사용하면
IconButton(onClick = {
isFavorite = !isFavorite
}
isFavorite.value 가 아닌 isFavorite 만으로도 값 변경 가능.
ImageCard()를 재사용하기 위해서는
isFavorite이 외부에서 선언되어야 한다
// 컴포즈가 시작되는 영역은 setContent 부터!
setContent {
// Icon 상태를 기억해줄 변수 - 컴포즈에서는 Boolean이 아닌 State 사용
// value 값을 자동으로 가져오도록 getValue, setValue import
// 자동 임포트가 안되므로 직접 해야함 -> by 사용 가능
var isFavorite by rememberSaveable {
mutableStateOf(false)
}
ImageCard(
isFavorite = isFavorite
)
}
}
}
@Composable
fun ImageCard(
isFavorite: Boolean,
) {
ImageCard에서 isFavorite 선언,
setContent에서 상태 기억 변수 선언 → 재사용 가능
이때, ImageCard에 들어오는 isFavorite은 변수가 아니라 상수이므로 값이 변화할 수 없다
IconButton(onClick = {
isFavorite = !isFavorite
}
isFavorite에서 에러 발생
콜백을 만든다 !
@Composable
fun ImageCard(
isFavorite: Boolean,
// 콜백 만들기 : 콜백으로 돌려줄 값은 Boolean, return은 없음
onTabFavorite: (Boolean) -> Unit,
)
IconButton(onClick = {
onTabFavorite(!isFavorite)
}
onClick 수정
setContent {
// Icon 상태를 기억해줄 변수 - 컴포즈에서는 Boolean이 아닌 State 사용
// value 값을 자동으로 가져오도록 getValue, setValue import
// 자동 임포트가 안되므로 직접 해야함 -> by 사용 가능
var isFavorite by rememberSaveable {
mutableStateOf(false)
}
ImageCard(
isFavorite = isFavorite,
) {favorite ->
isFavorite = favorite
}
ImageCard에서 isFavorite 값을 변경해준다
Modifier 도 재사용 가능하게 외부에서 설정
fun ImageCard(
modifier: Modifier = Modifier,
isFavorite: Boolean,
// 콜백 만들기 : 콜백으로 돌려줄 값은 Boolean, return은 없음
onTabFavorite: (Boolean) -> Unit,
)
setContent {
// Icon 상태를 기억해줄 변수 - 컴포즈에서는 Boolean이 아닌 State 사용
// value 값을 자동으로 가져오도록 getValue, setValue import
// 자동 임포트가 안되므로 직접 해야함 -> by 사용 가능
var isFavorite by rememberSaveable {
mutableStateOf(false)
}
ImageCard(
modifier = Modifier
.fillMaxWidth(0.5f)
.padding(16.dp),
isFavorite = isFavorite,
) {favorite ->
isFavorite = favorite
}
}
TextField
setContent {
// 텍스트 필드에 입력하면 값이 동적으로 변하도록 변수 지정
val textValue = remember { // remember로 값을 저장
mutableStateOf("") // 값을 지정
}
Column (
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
// 텍스트를 입력받는 TextField, 값을 지정하는 value, 값이 변했을ㄷ 때의 함수 onValueChange
TextField(
value = textValue.value,
onValueChange = {
textValue.value = it
},
)
Button(onClick = { }) {
Text("클릭!")
}
}
}
TextField의 value 값을 기억하는 변수를 만들어서 mutableState로
그리고 값이 변하면 textValue의 value를 TextField에서 볼 수 있게
MutableState의 Operator를 이용해 구조분해 하자
val (text, setValue) = remember { // remember로 값을 저장
mutableStateOf("") // 값을 지정
}
text : String으로 할당
setValue : String을 받아서 Unit으로 리턴하는 형태
TextField(
value = text,
onValueChange = setValue,
)
위와 같이 구조분해 할 수 있다.
Scaffold
: 머티리얼 구조의 뼈대가 되는 컴포즈
→ 스낵바, 플로팅액션버튼 등 사용할 때 Scaffold로 감싸서 사용
스낵바 사용을 위해 기억할 변수 지정
// 스낵바 사용을 위해 최근의 상태를 저장
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState,
) {
스낵바는 다음과 같이 띄울 수 있는데
scaffoldState.snackbarHostState.showSnackbar("Hello $text")
showSnackbar 부분에서 빨간줄의 띄워진다!
showSnackbar는 suspend 함수로, 정지함수다.
suspend 함수는 코루틴을 사용해야한다
setContent {
// 텍스트 필드에 입력하면 값이 동적으로 변하도록 변수 지정
// text는 String으로 할당, setValue는 String을 받아서 Unit으로 리턴하는 형태
val (text, setValue) = remember { // remember로 값을 저장
mutableStateOf("") // 값을 지정
}
// 스낵바 사용을 위해 최근의 상태를 저장
val scaffoldState = rememberScaffoldState()
// 컴포즈에서 코루틴 스코프 얻기
val scope = rememberCoroutineScope()
컴포즈에서는 rememberCoroutineScope()를 이용해 코루틴 스코프를 쉽게 지정할 수 있다
Button(onClick = {
// 코루틴 스코프 실행, suspend 함수 실행 가능
scope.launch{
scaffoldState.snackbarHostState.showSnackbar("Hello $text")
}
})
scope.launch 안에서는 suspend 함수가 작동하는 모습
키보드 내리기
// 키보드 내리기
val keyboardController = LocalSoftwareKeyboardController.current
키보드컨트롤러 변수를 선언하면 LocalSoftwareKeyboardController.current에서 에러가 발생한다
아직 실험중인 기능이기 때문!
@OptIn(ExperimentalComposeUiApi::class)
를 선언하여 실험중인 기능을 사용한다고 명시.
Button(onClick = {
// null값일 수 있으므로 ? 붙여서 안전하게 호출
keyboardController?.hide()
// 코루틴 스코프 실행, suspend 함수 실행 가능
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Hello $text")
}
})
다음과 같이 키보드컨트롤러를 hide하면 버튼 클릭시 키보드가 내려간다 !
'개발일지' 카테고리의 다른 글
[Kotlin] Compose 입문 #4 - ViewModel (0) | 2023.06.22 |
---|---|
[Kotlin] Compose 입문 #3 - Navigation, 화면 전환, 값 넘겨주기 (0) | 2023.06.22 |
[Kotlin] Compose 입문 #1 - Column, Row, 컴포저블, 리스트 (0) | 2023.06.20 |
[Kotlin] 형변환과 배열, 타입추론과 함수 (0) | 2023.04.19 |
[Android] Android Architecture Pattern (0) | 2023.04.19 |