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.
i 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)?,
) {
}
}