24.01.31 Compose에서 스낵바 출력하기

KSang·2024년 1월 30일
0

TIL

목록 보기
46/101

TextField와 구조분해 ,Button ,스낵바와 코루틴스코프

image

이번에 editText처럼 값을 입력받을수 있는 TextField와 Button을 컴포즈로 만들어볼것이다

TextField

일단 TextField를 Column안에 넣어주자

class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalMaterial3Api::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column (
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                TextField( 
                    value = "" , 
                    onValueChange = { }, 
                )
            }
        }
    }
}

TextField를 처음 선언했을때 에러가 났다.

API안정화가 안되어 있다고 했는데 버전이 바뀌면서 뭔가 바뀐 느낌이다

현재 1.4.3 버전을 쓰고있는데 과거 다른 버전을 쓰는 영상들을 보면 별문제 없이 쓴 것처럼 보였는데 에러가떠서 @OptIn(ExperimentalMaterial3Api::class)를 추가해줬다.

안정화가 안됐기 때문에 BasicTextField를 쓰면 된다고 하는데 그러면 여러가지 설정 해줘야 하기 때문에 어노테이션을 사용해서 TextField를 사용했다

value는 텍스트 필드에 표시되는 값이고

onValueChange는 값이 변했을때 작성하는 부분이다

여기서 사용자가 Text를 입력해 값이 변하고 그걸 필드에 표시하려면 상태를 설정해야한다

            val textValue = remember {
                mutableStateOf("")
            }

            Column (
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                TextField(
                    value = textValue.value , 
                    onValueChange = {
                                    textValue.value = it
                    }, 
                )

이런 식으로 넣어주면 필드에 값을입력하고 변경할수 있다.

구조분해

textValue를 보면 mutableStateOf로 초기화 되어 있는데

MutableState는 이런식으로 구성되어 있다.

@Stable
interface MutableState<T> : State<T> {
    override var value: T
    operator fun component1(): T
    operator fun component2(): (T) -> Unit
}

인터페이스로 이루어져있는데,

value로 값을 받고 오퍼레이터 component1 로 값을 뱉어내고 , 2는 람다로 되어있다.

component1() 함수는 MutableState의 value를 반환한다. 즉, MutableState의 현재 값을 가져온다.

component2() 함수는 value를 설정하는 람다를 반환한다. 이 람다는 새로운 값을 받아서 MutableState의 value를 업데이트한다.

이런식으로 구성되어 있는 이유는 코틀린의 구조 분해를 위해서 이렇게 만들어져있는데

구조 분해 선언을 사용하면

val (text, setValue) = remember {
                mutableStateOf("")
            }
            Column (
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                TextField( 
                    value = text ,
                    onValueChange = setValue, 
                )

현재 값을 value로 onValueChange를 setValue로 이렇게 표현할 수 있다.

Button

버튼부분은 기존에 사용한것처럼 Button을 이용하면 구현할 수 있다.

                Button(onClick = { /*TODO*/ }) {
                    Text("클릭") 
                }

Text부분에서 한참 헤맸는데 에러가 계속떴다.

alt + enter로 임포트 할 수 있는건 전부 다했는데 저렇게 구현이 안됐다.

한참 헤매다가 import androidx.compose.material3.Text 를 직접 입력해주니 됐다,,

이제 스낵바를 띄워 줄건데 머테리얼 디자인의 뼈대가 되는 컴포즈 사용할거다

플로팅 버튼이나 스낵바 같은경우 Scaffold를 이용한다

        Scaffold(){
            Column (
                ...
        }

Scaffold를 만들어주고 그안에 Column을 전부 넣어준다.

과거엔 Scaffold안의 scaffoldState를 이용해서 스낵바를 띄워줬는데 버전이 업데이트 되면서 현재는

scaffoldState 랑 SnackbarHost가 분리되고, Scaffold에 scaffoldState가 포함되지 않게 되었기 때문에

snackbarHost를 이용해서 스낵바를 띄워 줄거다

            val snackbarHostState = remember { //호스트와 그 상태를 정의
                SnackbarHostState()
            }
            
            Scaffold( snackbarHost = {
                                     SnackbarHost(snackbarHostState)
            }) Column(
                   ...

                    Button(onClick = {
                            snackbarHostState.showSnackbar(message = "Hello $text")
                    }) {
                        Text("클릭") 
                    }

버튼을 클릭했을때 스낵바가 등장하고 메세지를 띄우게 만들어 줬다.

그런데 이러면 showSnackbar쪽에 에러 메세지가 뜰 것이다.

showSnackbar를 보면 public final suspend fun showSnackbar( suspend 함수로 되어있는걸 볼수 있다.

코루틴을 사용해야하는데 컴포즈 안에서 쉽게 선언 할 수 있다.

val snackbarScope = rememberCoroutineScope()

또 리멤버를 쓰면 뭐가 계속나온다.

            val snackbarScope = rememberCoroutineScope() // 코루틴에서 스낵바를 불러야함
            val snackbarHostState = remember { //호스트와 그 상태를 정의
                SnackbarHostState()
            }
            Scaffold( snackbarHost = {
                                     SnackbarHost(snackbarHostState)
            }) {
                Column(
                    modifier = Modifier.fillMaxSize(),
                    verticalArrangement = Arrangement.Center,
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    TextField(
                        value = text,
                        onValueChange = setValue,
                    )
                    Button(onClick = {
                        snackbarScope.launch {
                            snackbarHostState.showSnackbar(message = "Hello $text")
                        }
                    }) {
                        Text("클릭")
                    }
                }
            }

image

거슬리는게 있는데 입력을하고 키보드가 올라와 있어서 키보드를 내려야 스낵바가 보인다.

이 키보드를 클릭했을때 내려주자

            val keyboardController = LocalSoftwareKeyboardController.current

키보드 컨트롤러를 이런식으로 만들어주고

                    Button(onClick = {
                        keyboardController?.hide()

버튼 부분에 추가해주면 된다.

0개의 댓글