xml의 EditText는 컴포즈에서 TextField가 되었다.
처음 TextField를 사용하면 당황스러운 점이, 기본적으로 입력이 되지 않는다.
컴포즈는 입력값도 직접 변수로 통제해줘야 하기 때문이다.
따로 String에 대한 MutableState 변수 등을 만들어 관리해주어야 하는데, 여러 방법이 있다.
val textValue = remember { mutableStateOf("") }기본적으로는 이렇게 변수를 만들어서 TextField의 매개변수로는
value = textValue.value,
onValueChange = { textValue.value = it }
이런 식으로 할 수 있다.
여기에서 한발 더 나아가면, delegate 문법을 사용하여 좀 더 편하게 사용할 수 있다.
var textValue by remember { mutableStateOf("") }
TextField(
value = textValue,
onValueChange = { textValue = it }
)
val (text, setText) = remember { mutableStateOf("") }구조분해를 이용하는 방법도 있다.
value = text,
onValueChange = setText
게터와 세터가 구조분해되어 받아져서, value와 onValueChange에 각각 넣어주면 된다.
val textValue = remember { mutableStateOf(TextFieldValue()) }TextFieldValue를 이용하는 방법도 있다.
value = textValue.value,
onValueChange = { textValue.value = it }
마찬가지로 delegate와 구조분해 역시 적용 가능하다.
그렇다면 String 대신 TextFieldValue를 사용하는 이점은 무엇일까?
대표적으로 selection 기능이 있다. 문자열에서 선택된 범위를 알려주는 기능으로, TextRange 타입이고 어디에서 어디까지 선택했는지를 나타낸다. (start가 end보다 클 수 있다.)
getTextBeforeSelection, getSelectedText, getTextAfterSelection으로 선택 영역 전의 문자열, 선택 영역 문자열, 선택 영역 후의 문자열을 받을 수 있다.
(getSelectedText는 파라미터가 없으며, 나머지 둘은 maxChars 값을 줘야 한다.)
이외에도 copy 기능을 지원하고 Saver를 제공하는 등의 편의성이 있다.
그러나 정말 알 수 없는 게 있는데, TextField에 초기값이 있는 경우, TextField를 처음 클릭하면 커서가 맨 앞으로 가버린다. 한참을 찾아봐도 해결법을 찾지 못했는데, 추측하기로는 onValueChange = { textState = it }이 커서를 옮길 때(selection 값이 바뀜)에도 작동하는데 이 때 새로 들어오는 it이 처음에 커서가 0 위치에 있기 때문에 그런 것 같다. 그렇다고 커서 위치를 임의로 제한하면 커서를 옮길 수가 없게 되어버린다.
이 문제를 해결할 방법을 아시는 분이 있다면 부디 댓글 남겨주시면 감사하겠습니다...