handwritingDetector
fun Modifier.handwritingDetector(callback: () -> Unit) =
if (isStylusHandwritingSupported) {
this.stylusHoverIcon(handwritingPointerIcon, false, HandwritingBoundsExpansion)
.then(HandwritingDetectorElement(callback))
} else {
this
}
Configures an element to act as a handwriting detector which detects stylus handwriting and delegates handling of the recognised text to another element.
Stylus movement on the element will start a handwriting session, and trigger the callback
. The
callback
implementation is expected to show and focus a text input field with a
handwritingHandler
modifier which can handle the recognized text from the handwriting session.
A common use case is a component which looks like a text input field but does not actually
support text input itself, and clicking on this fake text input field causes a real text input
field to be shown. To support handwriting initiation in this case, this modifier can be applied
to the fake text input field to configure it as a detector, and a handwritingHandler
modifier
can be applied to the real text input field. The callback
implementation is typically the same
as the onClick
implementation for the fake text field's clickable
modifier, which shows and
focuses the real text input field.
This function returns a no-op modifier on API levels below Android U (34) as stylus handwriting is not supported.
Parameters
callback | a callback which will be triggered when stylus handwriting is detected |
Code Examples
HandwritingDetectorSample
@Composable
fun HandwritingDetectorSample() {
var openDialog by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
Column(
Modifier.imePadding().requiredWidth(300.dp).verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
"This is not an actual text field, but it is a handwriting detector so you can use " +
"a stylus to write here."
)
Spacer(Modifier.size(16.dp))
Text(
"Fake text field",
Modifier.fillMaxWidth()
.handwritingDetector { openDialog = !openDialog }
.padding(4.dp)
.border(
1.dp,
MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
RoundedCornerShape(4.dp),
)
.padding(16.dp),
color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
)
}
if (openDialog) {
Dialog(onDismissRequest = { openDialog = false }) {
Card(modifier = Modifier.width(300.dp), shape = RoundedCornerShape(16.dp)) {
Column(
modifier = Modifier.padding(24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text("This text field is a handwriting handler.")
Spacer(Modifier.size(16.dp))
val state = remember { TextFieldState() }
BasicTextField(
state = state,
modifier =
Modifier.fillMaxWidth()
.focusRequester(focusRequester)
.handwritingHandler(),
decorator = { innerTextField ->
Box(
Modifier.padding(4.dp)
.border(
1.dp,
MaterialTheme.colors.onSurface,
RoundedCornerShape(4.dp),
)
.padding(16.dp)
) {
innerTextField()
}
},
)
}
}
val windowInfo = LocalWindowInfo.current
LaunchedEffect(windowInfo) {
snapshotFlow { windowInfo.isWindowFocused }
.collect { isWindowFocused ->
if (isWindowFocused) {
focusRequester.requestFocus()
}
}
}
}
}
}