MAUI Blazor Android 输入框软键盘遮挡问题2.0

[删除(380066935@qq.com或微信通知)]

更好的阅读体验请查看原文:https://www.cnblogs.com/Yu-Core/p/17525807.html

前言

关于MAUI Blazor Android 输入框软键盘遮挡问题,之前的文章已经有了答案,MAUI Blazor Android 输入框软键盘遮挡问题

但是这个方案一直存在一点小的瑕疵

在小窗模式下,界面的高度始终不正确

所以本篇文章重点解决这个问题

特别感谢这篇文章 Android webView输入框软键盘遮挡问题-终极解决方案(不好使你打我) ,上一篇文章忘记感谢了,非常抱歉。

1. 小窗模式界面高度不正确

问题展示

可以很清楚的看到,小窗模式下,下面那一部分被吃掉了。这个是无法滚动的。

也就是说,界面渲染的高度实际上是大于小窗屏幕的高度。

那一部分哪去了,经过简单的调试,发现恰恰就是状态栏的高度

也就是代码中的这一部分

static int ComputeUsableHeight()
{
    Rect rect = new Rect();
    MChildOfContent?.GetWindowVisibleDisplayFrame(rect);
    return rect.Bottom - rect.Top;
}

小窗模式时,rect.Top返回的永远是0,而不是状态栏高度

解决办法

我们重新写一个获取状态栏高度的方法,用它去替代rect.Top

static int ComputeUsableHeight()
{
    Rect rect = new Rect();
    MChildOfContent?.GetWindowVisibleDisplayFrame(rect);
    return rect.Bottom - GetStatusBarHeight();
}

static int GetStatusBarHeight()
{
    int result = 0;
    Resources resources = Activity.Resources ?? throw new InvalidOperationException("Activity Resources can't be null.");
    int resourceId = resources.GetIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0)
    {
        result = resources.GetDimensionPixelSize(resourceId);
    }
    return result;
}

2. 全屏模式

然而又出现了新的问题,如果取消状态栏,那么界面高度又不正确了

很快找到解决办法

static int ComputeUsableHeight()
    {
        Rect rect = new Rect();
        MChildOfContent.GetWindowVisibleDisplayFrame(rect);
        if (IsImmersiveMode())
        {
            return rect.Bottom;
        }
        else
        {
            return rect.Bottom - GetStatusBarHeight();
        }
    }
	
static bool IsImmersiveMode()
    {
        View decorView = Activity.Window.DecorView;
        int uiOptions = (int)decorView.SystemUiVisibility;
        return (uiOptions & (int)SystemUiFlags.Immersive) == (int)SystemUiFlags.Immersive;
    }

4. 最终全部代码

Platform/Android/WebViewSoftInputPatch.cs

using Android.Content.Res;
using Android.Views;
using Android.Widget;
using System.Runtime.Versioning;
using static Android.Resource;
using Activity = Android.App.Activity;
using Rect = Android.Graphics.Rect;
using View = Android.Views.View;

namespace MauiBlazor3.Platform.Android;

[SupportedOSPlatform("Android")]
public static class WebViewSoftInputPatch
{
    static Activity Activity => Microsoft.Maui.ApplicationModel.Platform.CurrentActivity ?? throw new InvalidOperationException("Android Activity can't be null.");
    static View MChildOfContent;
    static FrameLayout.LayoutParams FrameLayoutParams;
    static int UsableHeightPrevious = 0;

    public static void Initialize()
    {
        FrameLayout content = (FrameLayout)Activity.FindViewById(Id.Content);
        MChildOfContent = content.GetChildAt(0);
        MChildOfContent.ViewTreeObserver.GlobalLayout += (s, o) => PossiblyResizeChildOfContent();
        FrameLayoutParams = (FrameLayout.LayoutParams)MChildOfContent?.LayoutParameters;
    }

    static void PossiblyResizeChildOfContent()
    {
        int usableHeightNow = ComputeUsableHeight();
        if (usableHeightNow != UsableHeightPrevious)
        {
            int usableHeightSansKeyboard = MChildOfContent.RootView.Height;
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference < 0)
            {
                usableHeightSansKeyboard = MChildOfContent.RootView.Width;
                heightDifference = usableHeightSansKeyboard - usableHeightNow;
            }

            if (heightDifference > usableHeightSansKeyboard / 4)
            {
                FrameLayoutParams.Height = usableHeightSansKeyboard - heightDifference;
            }
            else
            {
                FrameLayoutParams.Height = usableHeightNow;
            }
        }

        MChildOfContent.RequestLayout();
        UsableHeightPrevious = usableHeightNow;
    }

    static int ComputeUsableHeight()
    {
        Rect rect = new Rect();
        MChildOfContent.GetWindowVisibleDisplayFrame(rect);
        if (IsImmersiveMode())
        {
            return rect.Bottom;
        }
        else
        {
            return rect.Bottom - GetStatusBarHeight();
        }
    }

    static int GetStatusBarHeight()
    {
        int result = 0;
        Resources resources = Activity.Resources;
        int resourceId = resources.GetIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0)
        {
            result = resources.GetDimensionPixelSize(resourceId);
        }
        return result;
    }

    static bool IsImmersiveMode()
    {
        View decorView = Activity.Window.DecorView;
        int uiOptions = (int)decorView.SystemUiVisibility;
        return (uiOptions & (int)SystemUiFlags.Immersive) == (int)SystemUiFlags.Immersive;
    }
}


Platform/Android/MainActivity.cs

protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        WebViewSoftInputPatch.Initialize();
    }