From 92b60deac0caca45c8b05f3724671345b9ab7c46 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 16 Sep 2026 11:33:36 +0200 Subject: [PATCH] Fix tastiera che copre il campo di scrittura Da Android 15 (API 35+) l'edge-to-edge e' forzato e adjustResize non ridimensiona piu' la finestra: la tastiera si limita a coprire la BlazorWebView. Con il layout rigido (html overflow:hidden, #app 100vh, page/main height:100% overflow:hidden) nemmeno il browser riesce a portare in vista il campo col focus. - MainActivity: WindowSoftInputMode AdjustResize|StateHidden e listener sugli WindowInsets che applica al content view il padding bottom pari all'inset IME (meno quello delle system bars, gia' coperto da SafeAreaEdges in MainPage), cosi' il 100vh si ricalcola. - main.js: su focusin e visualViewport resize porta il campo attivo al centro con scrollIntoView, necessario per i contenitori scrollabili. Co-Authored-By: Claude Opus 5 (1M context) --- SteUp.Maui/Platforms/Android/MainActivity.cs | 35 ++++++++++++++++++++ SteUp.Shared/wwwroot/js/main.js | 35 ++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/SteUp.Maui/Platforms/Android/MainActivity.cs b/SteUp.Maui/Platforms/Android/MainActivity.cs index 9e73182..9d5aaa8 100644 --- a/SteUp.Maui/Platforms/Android/MainActivity.cs +++ b/SteUp.Maui/Platforms/Android/MainActivity.cs @@ -1,14 +1,49 @@ using Android.App; using Android.Content.PM; +using Android.OS; +using Android.Views; +using AndroidX.Core.View; namespace SteUp.Maui { [Activity( Theme = "@style/Maui.SplashTheme", MainLauncher = true, + WindowSoftInputMode = SoftInput.AdjustResize | SoftInput.StateHidden, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] public class MainActivity : MauiAppCompatActivity { + protected override void OnCreate(Bundle? savedInstanceState) + { + base.OnCreate(savedInstanceState); + + // Da Android 15 (API 35) il edge-to-edge e' forzato e adjustResize non ridimensiona + // piu' la finestra: la tastiera si limita a coprire la WebView. Riduciamo noi il + // content view dell'altezza dell'IME cosi' il layout Blazor (100vh) si ricalcola. + if (FindViewById(Android.Resource.Id.Content) is { } content) + ViewCompat.SetOnApplyWindowInsetsListener(content, new ImeInsetsListener()); + } + + private sealed class ImeInsetsListener : Java.Lang.Object, IOnApplyWindowInsetsListener + { + public WindowInsetsCompat OnApplyWindowInsets(Android.Views.View? v, WindowInsetsCompat? insets) + { + if (v is null || insets is null) + return insets!; + + var ime = insets.GetInsets(WindowInsetsCompat.Type.Ime()).Bottom; + var systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars()).Bottom; + + // La barra di navigazione e' gia' gestita da SafeAreaEdges in MainPage: + // teniamo solo la parte di tastiera che la eccede, per non sommare due volte. + var bottom = System.Math.Max(0, ime - systemBars); + + if (v.PaddingBottom != bottom) + v.SetPadding(v.PaddingLeft, v.PaddingTop, v.PaddingRight, bottom); + + return insets; + } + } } } diff --git a/SteUp.Shared/wwwroot/js/main.js b/SteUp.Shared/wwwroot/js/main.js index fbd9b20..ea1c5d7 100644 --- a/SteUp.Shared/wwwroot/js/main.js +++ b/SteUp.Shared/wwwroot/js/main.js @@ -95,3 +95,38 @@ document.addEventListener("DOMContentLoaded", () => { }, 600); } })(); + + +// Tastiera: porta il campo attivo dentro l'area visibile. +// Il layout e' a 100vh con overflow:hidden, quindi quando l'host riduce la +// WebView per la tastiera il browser non scrolla da solo sul campo col focus. +(function () { + const SELECTOR = 'input, textarea, [contenteditable="true"]'; + let pending = null; + + function scrollFocusedIntoView() { + const el = document.activeElement; + if (!el || !el.matches || !el.matches(SELECTOR)) return; + el.scrollIntoView({block: 'center', behavior: 'smooth'}); + } + + function schedule() { + clearTimeout(pending); + // attende la fine dell'animazione di apertura della tastiera e del relayout + pending = setTimeout(scrollFocusedIntoView, 300); + } + + document.addEventListener('focusin', function (event) { + if (event.target && event.target.matches && event.target.matches(SELECTOR)) { + schedule(); + } + }); + + // Il resize arriva quando la tastiera si apre/chiude o cambia altezza + // (es. passaggio a tastiera emoji o suggerimenti). + if (window.visualViewport) { + window.visualViewport.addEventListener('resize', schedule); + } else { + window.addEventListener('resize', schedule); + } +})();