最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Auto-Focus BasicTextField Without Cursor Jetpack compose - Stack Overflow

programmeradmin0浏览0评论

I'm building a screen in Jetpack Compose where I want a BasicTextField to be "active" as soon as the screen loads. By "active," I mean that the label should animate upward (just like it does when the field is focused) and the placeholder should be visible. However, I do not want the blinking cursor to appear until the user actually interacts with the BasicTextField.

Currently, my implementation auto-focuses the BasicTextField on launch using a FocusRequester, but this approach also brings up the cursor immediately, which is not the desired behavior.

Here’s a simplified version of my current code:

MainActivity.kt

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activitypose.setContent
import androidx.activity.enableEdgeToEdge
import androidxpose.foundation.interaction.MutableInteractionSource
import androidxpose.foundation.layout.Column
import androidxpose.foundation.layout.fillMaxSize
import androidxpose.foundation.layout.fillMaxWidth
import androidxpose.foundation.layout.height
import androidxpose.foundation.layout.padding
import androidxpose.foundation.text.BasicTextField
import androidxpose.foundation.text.input.TextFieldLineLimits
import androidxpose.foundation.text.input.TextFieldState
import androidxpose.foundation.text.input.rememberTextFieldState
import androidxpose.material3.ExperimentalMaterial3Api
import androidxpose.material3.Text
import androidxpose.material3.TextFieldDefaults
import androidxpose.runtime.Composable
import androidxpose.runtime.remember
import androidxpose.ui.Modifier
import androidxpose.ui.unit.dp

class MainActivity : ComponentActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            val stateOne = rememberTextFieldState(initialText = "Hellow")
            val stateTwo = rememberTextFieldState()
            BasicTextFieldExamples(
                stateOne,
                remember { MutableInteractionSource() },
                stateTwo,
                remember { MutableInteractionSource() },
            )
        }
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun BasicTextFieldExamples(
        stateOne: TextFieldState,
        firstInteractionSource: MutableInteractionSource,
        stateOTwo: TextFieldState,
        secondInteractionSource: MutableInteractionSource,
    ) {
        Column(
            Modifier
                .fillMaxSize()
                .padding(50.dp)
        ) {
            BasicTextField(
                state = stateOne,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                readOnly = true,
                interactionSource = firstInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOne,
                    enabled = true,
                    label = {
                        Text("First Name")
                    },
                    placeholder = {
                        Text("Example 1")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = firstInteractionSource,
                    outputTransformation = null
                )
            )
            BasicTextField(
                state = stateOTwo,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                interactionSource = secondInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOTwo,
                    enabled = true,
                    label = {
                        Text("Last Name")
                    },
                    placeholder = {
                        Text("Example 2")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = secondInteractionSource,
                    outputTransformation = null
                )
            )
        }
    }
}

I'm building a screen in Jetpack Compose where I want a BasicTextField to be "active" as soon as the screen loads. By "active," I mean that the label should animate upward (just like it does when the field is focused) and the placeholder should be visible. However, I do not want the blinking cursor to appear until the user actually interacts with the BasicTextField.

Currently, my implementation auto-focuses the BasicTextField on launch using a FocusRequester, but this approach also brings up the cursor immediately, which is not the desired behavior.

Here’s a simplified version of my current code:

MainActivity.kt

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            val stateOne = rememberTextFieldState(initialText = "Hellow")
            val stateTwo = rememberTextFieldState()
            BasicTextFieldExamples(
                stateOne,
                remember { MutableInteractionSource() },
                stateTwo,
                remember { MutableInteractionSource() },
            )
        }
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun BasicTextFieldExamples(
        stateOne: TextFieldState,
        firstInteractionSource: MutableInteractionSource,
        stateOTwo: TextFieldState,
        secondInteractionSource: MutableInteractionSource,
    ) {
        Column(
            Modifier
                .fillMaxSize()
                .padding(50.dp)
        ) {
            BasicTextField(
                state = stateOne,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                readOnly = true,
                interactionSource = firstInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOne,
                    enabled = true,
                    label = {
                        Text("First Name")
                    },
                    placeholder = {
                        Text("Example 1")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = firstInteractionSource,
                    outputTransformation = null
                )
            )
            BasicTextField(
                state = stateOTwo,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(56.dp),
                interactionSource = secondInteractionSource,
                decorator = TextFieldDefaults.decorator(
                    state = stateOTwo,
                    enabled = true,
                    label = {
                        Text("Last Name")
                    },
                    placeholder = {
                        Text("Example 2")
                    },
                    lineLimits = TextFieldLineLimits.Default,
                    interactionSource = secondInteractionSource,
                    outputTransformation = null
                )
            )
        }
    }
}
Share Improve this question edited Feb 5 at 20:46 Vivek Modi asked Feb 5 at 18:03 Vivek ModiVivek Modi 7,19118 gold badges101 silver badges224 bronze badges 7
  • Clone TextField() and implement what you want. – CommonsWare Commented Feb 5 at 18:37
  • Sorry @CommonsWare I don't know how to implement like that in TextField. – Vivek Modi Commented Feb 5 at 19:07
  • I do not know if you are using Compose Material or Compose Material3. At least with Compose Material, it looks like you would need to create a modified version of TextFieldDefaults.TextFieldDecorationBox() and use that for the decorationBox. That, in turn, is based on CommonDecorationBox(), and you would need to change the placeholder behavior. – CommonsWare Commented Feb 5 at 19:15
  • I updated my code and I'm using material 3. – Vivek Modi Commented Feb 5 at 20:47
  • Here is TextField() for Material3. The placeholder and label are controlled by TextFieldDefaults.decorator(). – CommonsWare Commented Feb 5 at 20:55
 |  Show 2 more comments

1 Answer 1

Reset to default 1

I think this might be what you need, using TextField rather than BasicTextField. You can customize the cursor colors via the provided TextFieldColors, so you can separately maintain a state that decides whether to show or hide the cursor, and hide it by setting the colors to transparent.

val focusRequester = remember { FocusRequester() }
LaunchedEffect("focus") { focusRequester.requestFocus() }

var showCursor by remember { mutableStateOf(false) }
val colors =
    if (showCursor) {
      TextFieldDefaults.colors()
    } else {
      TextFieldDefaults.colors()
          .copy(cursorColor = Color.Transparent, errorCursorColor = Color.Transparent)
    }

var text by remember { mutableStateOf("") }
TextField(
    value = text,
    colors = colors,
    onValueChange = { text = it },
    label = { Text(text = "Label") },
    placeholder = { Text(text = "Placeholder") },
    modifier =
        Modifier.focusRequester(focusRequester).pointerInput("key") {
          awaitPointerEventScope {
            awaitFirstDown(requireUnconsumed = false)
            showCursor = true
          }
        })
发布评论

评论列表(0)

  1. 暂无评论