Search code examples
kotlinandroid-jetpack-compose

Analog Textview.append("text")) on Jetpack Compose?


I want the text to be added to the previous one when the tracked value changes, rather than redrawn completely.

I looked through the methods in Basic Text and Text but didn't find anything. Previously I could implement this using Textview.append("text"))


Solution

  • First, you should consider whether you actually need LiveData in your case.

    It seems like you are coming from Android Views, but Compose follows a reactive approach, so you do barely need LiveData in Compose. Once you update the data, the UI will refresh to display the updated data by default.
    So in Compose, instead of modifying the View / Composable directly, you just update the data.
    See the last section in this post for alternatives to LiveData.

    When you are using LiveData to handle the text, you should declare the LiveData in your ViewModel. This ViewModel would look as follows:

    class MyViewModel : ViewModel() {
    
        private val _myLive = MutableLiveData("")    // modify this from ViewModel
        val myLive: LiveData<String> = _myLive       // observe this in Composable
    
        fun appendText(appendValue: String) {
            _myLive.value += appendValue
        }
    }
    

    Then, in your Composable, observe it like this:

    @Composable
    fun MainComposable(myViewModel: MyViewModel = viewModel()) {
        val mytext: String by myViewModel.myLive.observeAsState()
    
        Text(text = mytext)
        Button(
            onClick = { myViewModel.appendText("ABC") }
        ) {
            Text(text = "Click to append ABC")
        }
    }
    

    Without LiveData. you could achieve the same thing as in above code using this simpler code:

    class MyViewModel : ViewModel() {
    
        var myText: String by mutableStateOf("")       // observe this in Composable
    
        fun appendText(appendValue: String) {
            myText += appendValue
        }
    }
    
    @Composable
    fun MainComposable(myViewModel: MyViewModel = viewModel()) {
    
        Text(text = myViewModel.myText)
        Button(
            onClick = { myViewModel.appendText("ABC") }
        ) {
            Text(text = "Click to append ABC")
        }
    }
    

    Or, if you only need myText locally in a single Composable, do

    @Composable
    fun MainComposable(myViewModel: MyViewModel = viewModel()) {
    
        var myText by rememberSaveable { mutableStateOf("") }
    
        Text(text = myText)
        Button(
            onClick = { myText += "ABC" }
        ) {
            Text(text = "Click to append ABC")
        }
    }