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

发布时间 2023-07-04 21:47:33作者: Yu-Core

前言

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

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

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

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

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

1. 之前方案的整理

之前文章的代码有些乱,小大写以及空值判断都没有处理,强迫症表示很难受。

所以讨论新问题之前,先把之前的代码整理一遍。

using Android.Content.Res;
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;

[SupportedOSPlatform("Android")]
public static partial 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);
        if (MChildOfContent?.ViewTreeObserver == null) return;
        MChildOfContent.ViewTreeObserver.GlobalLayout += (s, o) => PossiblyResizeChildOfContent();
        FrameLayoutParams = (FrameLayout.LayoutParams?)MChildOfContent?.LayoutParameters;
    }

    static void PossiblyResizeChildOfContent()
    {
        if (MChildOfContent?.RootView == null) return;
        if (FrameLayoutParams == null) return;

        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);
        return rect.Bottom - rect.Top;
    }
}

Platforms/Android/MainActivity.cs中添加以下代码

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

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

问题展示

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

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

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

也就是代码中的这一部分

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;
}