How can I prevent a Jetpack Compose BasicTextField to get focused on long press? I want it to get focused on a normal tap. But not by a long press or a swipe gesture, for example. I am using the newest version of BasicTextField.
BasicTextField(
value = TextFieldValue(
text = "TEST TEST",
selection = TextRange("TEST TEST".length)
),
onValueChange = { newText -> },
singleLine = true,
textStyle = MaterialTheme.typography.body1
)
To give some context on why I need this: The BasicTextField is part of a lazylist item. Each item can be reordered by longpressing it. Each item can also be deleted by a swipe to dismiss gesture. So I don't want these user inputs to trigger the edit mode of the text field.
I already tried all the answers from ChatGPT, Claude and so on. Trying to ignore the longpress with emtpy pointerInput
modifiers does not work. I also played around with pointerInteropFilter
and focusRequester
, but to no avail.
How can I prevent a Jetpack Compose BasicTextField to get focused on long press? I want it to get focused on a normal tap. But not by a long press or a swipe gesture, for example. I am using the newest version of BasicTextField.
BasicTextField(
value = TextFieldValue(
text = "TEST TEST",
selection = TextRange("TEST TEST".length)
),
onValueChange = { newText -> },
singleLine = true,
textStyle = MaterialTheme.typography.body1
)
To give some context on why I need this: The BasicTextField is part of a lazylist item. Each item can be reordered by longpressing it. Each item can also be deleted by a swipe to dismiss gesture. So I don't want these user inputs to trigger the edit mode of the text field.
I already tried all the answers from ChatGPT, Claude and so on. Trying to ignore the longpress with emtpy pointerInput
modifiers does not work. I also played around with pointerInteropFilter
and focusRequester
, but to no avail.
2 Answers
Reset to default 0i think there is no direct way to do it so this might be helpful if it fits your usecase.
@Composable
fun DraggableTextField(
initialText: String = "Custom text",
longPressDurationMs: Long = 300,
) {
var textFieldValue by remember { mutableStateOf(TextFieldValue(initialText)) }
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
var canFocus by remember { mutableStateOf(true) }
var pressStartTime by remember { mutableStateOf<Long?>(null) }
var position by remember { mutableStateOf(Offset.Zero) }
// Handle press duration logic
LaunchedEffect(isPressed) {
if (isPressed) {
pressStartTime = System.currentTimeMillis()
} else {
pressStartTime?.let { startTime ->
val duration = System.currentTimeMillis() - startTime
if (duration > longPressDurationMs) {
canFocus = false
} else {
canFocus = true
}
}
pressStartTime = null
}
}
// making text selection appears transparent
val customTextSelectionColors = remember {
TextSelectionColors(
handleColor = Color.Transparent,
backgroundColor = Color.Transparent
)
}
CompositionLocalProvider(
LocalTextSelectionColors provides customTextSelectionColors,
LocalTextToolbar provides EmptyTextToolbar
) {
BasicTextField(
value = textFieldValue,
onValueChange = { textFieldValue = it },
interactionSource = interactionSource,
modifier = Modifier
.graphicsLayer(
translationX = position.x,
translationY = position.y
)
.fillMaxWidth()
.background(Color.Cyan)
.padding(vertical = 5.dp)
.focusProperties { this.canFocus = canFocus },
//decoration box needs to be used in order to be able to detect drag gesture
decorationBox = { innerTextField ->
Row(
Modifier
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
position += dragAmount
}
}
.border(1.dp, Color.Gray, shape = RectangleShape)
.padding(16.dp)
.fillMaxWidth().
) {
innerTextField()
}
}
)
}
}
//to remove copy/paste toolbar that appears on long press
object EmptyTextToolbar: TextToolbar {
override val status: TextToolbarStatus = TextToolbarStatus.Hidden
override fun hide() { }
override fun showMenu(
rect: Rect,
onCopyRequested: (() -> Unit)?,
onPasteRequested: (() -> Unit)?,
onCutRequested: (() -> Unit)?,
onSelectAllRequested: (() -> Unit)?,
) {
}
}
Since your BasicTextField is inside a LazyList item that supports drag reordering and swipe to dismiss, it is preventing the textfield from getting focus due to long press, but still allow normal taps to focus
TextFieldValue
instead of aTextFieldState
. Have you tried out the new version? Does it behave the same? Regardless, it would help if you added a little bit more context, like the LazyList and how your handle the item's longpress and swipe gestures so we can reproduce the issue. – tyg Commented Jan 28 at 1:40