Sunday, April 25, 2021

jetpack compose - TextField focus change listener

Compose TextField Focus Change Listener
TextFIeld is a widget of the android jetpack compose library. This widget is used for entering text and modifying text on an app screen. Android view system’s EditText is an equivalent of the jetpack compose TextField widget. TextField widget has a very easy API to request focus on it, remove focus from it and handle the focus change listener.

The ‘FocusRequester’ object is used in conjunction with ‘Modifier.focusRequester’ to send requests to change focus. So, we can use this Modifier object’s ‘focusRequester’ element to set the focus on a TextField widget programmatically.

FocusManager.clearFocus() method clear focus from the currently focused component and set the focus to the root focus modifier. So we can remove focus from a TextField using FocusManager.clearFocus() method. We have to create an instance of LocalFocusManager and call its clearFoucs() method to remove focus from TextField.

So, we can request focus for a TextField widget and also can remove focus from a TextField widget, then how we can handle the TextField focus change listener? Ok, this android jetpack compose tutorial will demonstrate to us how we can handle the TextField focus change listener.

Modifier object’s ‘onFocusChanged’ element observes focus state event. The Modifier.onFocusChanged is invoked when the specified widget’s focus state changes. So we can use the TextField widget modifier object’s ‘onFocusChanged’ element to handle or listen to the TextField focus change event.

In this tutorial, we show a message to the app interface while TextField’s focus change. When TextField gets focus we show a message and when TextField loses focus we display another message to the app user.

This tutorial code is written in an android studio IDE. Copy the code and paste it into your android studio IDE main activity file and run it on an emulator device to test how we handle the TextField widget’s focus change listener. Screenshots are also displayed at the bottom of the code snippets. Look at those to understand the code entirely.
MainActivity.kt

package com.cfsuman.jetpackcompose

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MainContent()
        }
    }


    @Composable
    fun MainContent(){
        Column(
            Modifier
                .background(Color(0xFFEDEAE0))
                .fillMaxSize()
                .padding(32.dp),
            verticalArrangement = Arrangement.spacedBy(24.dp)
        ) {
            var textState by remember { mutableStateOf(TextFieldValue()) }
            var focusState by remember { mutableStateOf("") }

            val localFocusManager = LocalFocusManager.current
            val focusRequester = FocusRequester()

            Text(
                text = focusState,
                fontSize = 22.sp,
                fontFamily = FontFamily.Monospace,
                color = Color(0xFF0047AB)
            )

            OutlinedTextField(
                value = textState,
                onValueChange = { textState = it },
                label = { Text(text = "Input your name") },
                modifier = Modifier
                    .focusRequester(focusRequester)
                    .fillMaxWidth()
                    .onFocusChanged {
                        focusState = if (it.isFocused) {
                            "TextField is focused."
                        } else {
                            "TextField has no focus."
                        }
                    },
            )

            Button(onClick = {
                focusRequester.requestFocus()
            }) {
                Text(text = "Request Focus")
            }

            Button(onClick = {
                localFocusManager.clearFocus()
            }) {
                Text(text = "Clear Focus")
            }
        }
    }


    @Preview
    @Composable
    fun ComposablePreview(){
        //MainContent()
    }
}