Wie lösche ich den TextField-Fokus beim Schließen der Tastatur und verhindere, dass zwei Rückdrücke erforderlich sind, um die App in Jetpack Compose zu beenden?
Lesezeit: 6 Minuten
Pylyp Dukhov
Ich verwende BasicTextField.
Wenn ich mit der Bearbeitung beginne, wird die Schaltfläche „Zurück“ zur Schaltfläche „Tastatur ausblenden“ (Pfeil nach unten).
Beim ersten Drücken der Zurück-Taste wird die Tastatur ausgeblendet, aber der Fokus liegt immer noch auf dem Textfeld. Beide onFocusChanged und BackPressHandler Handler werden nicht angerufen.
Zweites Drücken der Zurück-Taste löscht den Fokus: onFocusChanged heißt und BackPressHandler ist nicht.
Beim dritten Mal funktioniert BackHandler einwandfrei. Ich habe es nur zum Testen verwendet, ich sollte es hier nicht brauchen, es wurde erwartet, dass der Fokus nach dem ersten Antippen der Zurück-Taste verloren geht
@mmm111mmm aus dem Gespräch rein Thema verfassen Ich verstehe, dass nach dem Fix Second Back die App geschlossen wird, aber das Schließen der Tastatur wird den Fokus immer noch nicht löschen, was immer noch nicht das ist, was ich in meiner App erwarte
– Pylyp Dukhov
24. August 2021 um 6:05 Uhr
Pylyp Dukhov
Da ist ein Thema verfassen mit fokussiertem Textfeld verhindert, dass die Zurück-Schaltfläche die App schließt, wenn die Tastatur ausgeblendet ist. Es ist als behoben markiert, wird aber in einer zukünftigen Version enthalten sein, nicht in 1.0
Aber so wie ich es verstehe, ist die Tatsache, dass das Textfeld den Fokus nicht verliert, nachdem die Tastatur geschlossen wurde, ein beabsichtigtes Verhalten auf Android (wegen einer möglichen angeschlossenen Tastatur? Ich habe den Grund nicht verstanden). Und so funktioniert es auch im alten Android-Layout
Es scheint mir seltsam, also kam ich mit dem folgenden Modifikator, der den Fokus aufgibt, wenn die Tastatur verschwindet:
fun Modifier.clearFocusOnKeyboardDismiss(): Modifier = composed {
var isFocused by remember { mutableStateOf(false) }
var keyboardAppearedSinceLastFocused by remember { mutableStateOf(false) }
if (isFocused) {
val imeIsVisible = LocalWindowInsets.current.ime.isVisible
val focusManager = LocalFocusManager.current
LaunchedEffect(imeIsVisible) {
if (imeIsVisible) {
keyboardAppearedSinceLastFocused = true
} else if (keyboardAppearedSinceLastFocused) {
focusManager.clearFocus()
}
}
}
onFocusEvent {
if (isFocused != it.isFocused) {
isFocused = it.isFocused
if (isFocused) {
keyboardAppearedSinceLastFocused = false
}
}
}
}
ps Sie müssen installieren Begleiter-Einsätze Abhängigkeit für LocalWindowInsets.current.ime
Pss Seit Komponieren 1.2.0-alpha03, Begleiter-Einsätze wurde meist eingezogen Stiftung komponierenKasse Migrationsleitfaden für mehr Details. LocalWindowInsets.current.ime sollte durch ersetzt werden WindowInsets.ime.
Verwendungszweck:
BasicTextField(
value = valueState.value,
onValueChange = {
valueState.value = it
},
modifier = Modifier
.clearFocusOnKeyboardDismiss()
)
Eigentlich bekomme ich das nicht zum Laufen LocalWindowInsets.current.ime.isVisible gibt immer false zurück, wenn ich die Soft-Tastatur öffne und schließe. Zumindest im Emulator.
– mmm111mm
19. August 2021 um 11:22 Uhr
@mmm111mmm bist du gefolgt WindowCompat.setDecorFitsSystemWindows(window, false) Notiz von accompanist insets?
– Pylyp Dukhov
19. August 2021 um 11:27 Uhr
Vielen Dank. Und ich fügte hinzu ProvideWindowInsets. Jetzt ist mein Problem, meinen Bildschirm zu gestalten, jetzt werden die Statusleiste und die untere Navigationsleiste nicht berücksichtigt …
– mmm111mm
19. August 2021 um 11:42 Uhr
@mmm111mmm, wenn Sie nicht vorhaben, mit ihnen zu interagieren, fügen Sie einfach hinzu systemBarsPadding für die ganze app, so etwas wie diese. Andernfalls müssen Sie diese Polsterung bei Bedarf zu jedem einzelnen Bildschirm hinzufügen
– Pylyp Dukhov
19. August 2021 um 11:46 Uhr
Ja, das funktioniert, aber wenn ich jetzt die Tastatur mit einem am unteren Bildschirmrand angehängten Textfeld öffne, wird das Textfeld jetzt von der Tastatur verdeckt, wie ich es verwende android:windowSoftInputMode="adjustResize. Dies ist die einzige funktionierende Lösung, die ich finden kann. Aber ich denke, es ist ein Problem mit Compose, und das ist jetzt zu komplex: Entfernen Sie Fenstereinschübe, damit Sie das Öffnen und Schließen einer Tastatur erkennen können, um den Fokus eines Textfelds aufzuheben, und Sie müssen auch Ihre App ohne Einschübe entwerfen.
– mmm111mm
19. August 2021 um 11:58 Uhr
Danke an alle Antworten hier. Nachdem Sie sich auf die Antworten hier bezogen haben, finden Sie hier eine Lösung ohne Verwendung einer Bibliothek
1. Erstellen Sie eine Erweiterung in View, um festzustellen, ob die Tastatur geöffnet ist oder nicht
fun View.isKeyboardOpen(): Boolean {
val rect = Rect()
getWindowVisibleDisplayFrame(rect);
val screenHeight = rootView.height
val keypadHeight = screenHeight - rect.bottom;
return keypadHeight > screenHeight * 0.15
}
2. Erstellen Sie einen beobachtbaren Zustand, um festzustellen, ob eine Tastatur geöffnet ist oder nicht
Dadurch werden globale Layout-Updates auf LocalView überwacht, bei denen wir bei jedem Ereignis den Status zum Öffnen/Schließen der Tastatur prüfen.
@Composable
fun rememberIsKeyboardOpen(): State<Boolean> {
val view = LocalView.current
return produceState(initialValue = view.isKeyboardOpen()) {
val viewTreeObserver = view.viewTreeObserver
val listener = OnGlobalLayoutListener { value = view.isKeyboardOpen() }
viewTreeObserver.addOnGlobalLayoutListener(listener)
awaitDispose { viewTreeObserver.removeOnGlobalLayoutListener(listener) }
}
}
3. Modifikator erstellen
Dieser Modifikator sorgt dafür, dass der Fokus auf sichtbare/unsichtbare Tastaturereignisse gelöscht wird.
fun Modifier.clearFocusOnKeyboardDismiss(): Modifier = composed {
var isFocused by remember { mutableStateOf(false) }
var keyboardAppearedSinceLastFocused by remember { mutableStateOf(false) }
if (isFocused) {
val isKeyboardOpen by rememberIsKeyboardOpen()
val focusManager = LocalFocusManager.current
LaunchedEffect(isKeyboardOpen) {
if (isKeyboardOpen) {
keyboardAppearedSinceLastFocused = true
} else if (keyboardAppearedSinceLastFocused) {
focusManager.clearFocus()
}
}
}
onFocusEvent {
if (isFocused != it.isFocused) {
isFocused = it.isFocused
if (isFocused) {
keyboardAppearedSinceLastFocused = false
}
}
}
}
4. Verwenden Sie es
Verwenden Sie es schließlich mit TextField zusammensetzbar
Ich habe eine wohl einfachere Lösung mit dem Baumbeobachter von Android gefunden.
Sie müssen keine andere Bibliothek verwenden oder die Einsätze aus Ihrem Layout entfernen.
Es löscht den Fokus beim Verfassen jedes Mal, wenn die Tastatur ausgeblendet ist.
Hoffentlich wird dies wann nicht mehr nötig sein diese es ist veröffentlicht worden.
class MainActivity : ComponentActivity() {
var kbClosed: () -> Unit = {}
var kbClosed: Boolean = false
override fun onCreate(state: Bundle?) {
super.onCreate(state)
setContent {
val focusManager = LocalFocusManager.current
kbClosed = {
focusManager.clearFocus()
}
MyComponent()
}
setupKeyboardDetection(findViewById<View>(android.R.id.content))
}
fun setupKeyboardDetection(contentView: View) {
contentView.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
contentView.getWindowVisibleDisplayFrame(r)
val screenHeight = contentView.rootView.height
val keypadHeight = screenHeight - r.bottom
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
kbClosed = false
// kb opened
} else if(!kbClosed) {
kbClosed = true
kbClosed()
}
}
}
}
Fügen Sie in einer Klasse, die von Application erbt, den folgenden Code hinzu, um zu erkennen, wann die Hauptaktivität erstellt wird, und fügen Sie den Code hinzu, der erkennt, wann die Tastatur angezeigt oder ausgeblendet wird:
import android.app.Activity
import android.app.Application
import android.content.res.Resources
import android.graphics.Rect
import android.os.Bundle
import android.util.DisplayMetrics
import androidx.compose.runtime.mutableStateOf
class App : Application() {
private val activityLifecycleTracker: AppLifecycleTracker = AppLifecycleTracker()
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(activityLifecycleTracker)
}
companion object {
val onKeyboardClosed = mutableStateOf(false)
}
/**
* Callbacks for handling the lifecycle of activities.
*/
class AppLifecycleTracker : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, p1: Bundle?) {
val displayMetrics: DisplayMetrics by lazy { Resources.getSystem().displayMetrics }
val screenRectPx = displayMetrics.run { Rect(0, 0, widthPixels, heightPixels) }
// Detect when the keyboard closes.
activity.window.decorView.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
activity.window.decorView.getWindowVisibleDisplayFrame(r)
val heightDiff: Int = screenRectPx.height() - (r.bottom - r.top)
onKeyboardClosed.value = (heightDiff <= 100)
}
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(p0: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
}
override fun onActivityDestroyed(p0: Activity) {
}
}
}
Fügen Sie die folgende Modifikatorerweiterung hinzu:
@Stable
fun Modifier.clearFocusOnKeyboardClose(focusManager: FocusManager): Modifier {
if (App.onKeyboardClosed.value) {
focusManager.clearFocus()
}
return this
}
Fügen Sie in Ihrem Composable einen Verweis auf den FocusManager hinzu und fügen Sie den Modifikator zu Ihrem TextField hinzu:
@Composable
fun MyComposable() {
val focusManager = LocalFocusManager.current
OutlinedTextField(
modifier = Modifier.clearFocusOnKeyboardClose(focusManager = focusManager)
)
}
Das TextField löscht seinen Fokus, wenn die Tastatur geschlossen wird.
10141200cookie-checkWie lösche ich den TextField-Fokus beim Schließen der Tastatur und verhindere, dass zwei Rückdrücke erforderlich sind, um die App in Jetpack Compose zu beenden?yes
Laut den Release Notes ist dies in 1.1.0 behoben jetc.dev/issues/077.html
– mmm111mm
24. August 2021 um 6:01 Uhr
@mmm111mmm aus dem Gespräch rein Thema verfassen Ich verstehe, dass nach dem Fix Second Back die App geschlossen wird, aber das Schließen der Tastatur wird den Fokus immer noch nicht löschen, was immer noch nicht das ist, was ich in meiner App erwarte
– Pylyp Dukhov
24. August 2021 um 6:05 Uhr