软键盘打开时如何防止特定的 Xamarin View 向上滚动?

How to prevent a specific Xamarin View up scrolling when soft keyboard is open?

我有以下 xamarin 布局模式:

<StackLayout>
    <Grid>...</Grid> <!-- TOP GRID - This must be fixed -->
    <ScrollView>...</ScrollView> <!-- This must scroll  -->
    <Grid><Entry></Entry>/Grid>  <!-- BOTTOM GRID - This must scroll -->
</StackLayout>

iOS 行为出人意料地如我所愿(这是一个聊天布局,所以顶部栏有我希望始终可见的图片和用户名),但是 android 行为向上滚动整个页面并仅保持 Entry 和 ScrollView 的底部可见,这几乎是我所需要的,但 Top Grid 正在消失。只有滚动视图和底部网格必须滚动。

我怎样才能做到这一点?

编辑 1

示例项目:

https://wetransfer.com/downloads/46b455cb7148189a0d1f84affa77b7e120210428144025/02b001

你能这样试试吗

基本的布局结构是这样的。

  <Grid RowDefinitions="50,*,Auto">
            <StackLayout Grid.Row="0" >
                <!-- Username and Profile image -->
            </StackLayout>
            <CollectionView Grid.Row="1">
                <!-- Your COllectionView -->
            </CollectionView>
            <controls:KeyboardView Grid.Row="2">
                <controls:KeyboardView.Margin>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="0,0,0,10" />
                        <On Platform="Android" Value="0,0,0,5" />
                    </OnPlatform>
                </controls:KeyboardView.Margin>
                <!-- Your entry and Send Button -->
            </controls:KeyboardView>

        </Grid>

在您的 PCL 上,创建 KeyboardView

 public class KeyboardView : Grid { }

在 ios 创建 KeyboardViewRenderer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreGraphics;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(KeyboardView), typeof(KeyboardViewRenderer))]
namespace YourAppName.iOS.CustomRender
{
    public class KeyboardViewRenderer : ViewRenderer
    {
        NSObject _keyboardShowObserver;
        NSObject _keyboardHideObserver;
        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                RegisterForKeyboardNotifications();
            }

            if (e.OldElement != null)
            {
                UnregisterForKeyboardNotifications();
            }
        }

        void RegisterForKeyboardNotifications()
        {
            if (_keyboardShowObserver == null)
                _keyboardShowObserver = UIKeyboard.Notifications.ObserveWillShow(OnKeyboardShow);
            if (_keyboardHideObserver == null)
                _keyboardHideObserver = UIKeyboard.Notifications.ObserveWillHide(OnKeyboardHide);
        }

        void OnKeyboardShow(object sender, UIKeyboardEventArgs args)
        {

            NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
            CGSize keyboardSize = result.RectangleFValue.Size;
            if (Element != null)
            {
                Element.Margin = new Thickness(0, 0, 0, keyboardSize.Height); //push the entry up to keyboard height when keyboard is activated

            }
        }

        void OnKeyboardHide(object sender, UIKeyboardEventArgs args)
        {
            if (Element != null)
            {
                Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
            }

        }


        void UnregisterForKeyboardNotifications()
        {
            if (_keyboardShowObserver != null)
            {
                _keyboardShowObserver.Dispose();
                _keyboardShowObserver = null;
            }

            if (_keyboardHideObserver != null)
            {
                _keyboardHideObserver.Dispose();
                _keyboardHideObserver = null;
            }
        }
    }
}

对于 Android 将此添加到 App.Xaml

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="KeyboardSample.App"
             xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
             android:Application.WindowSoftInputModeAdjust="Resize">
    <Application.Resources>
    </Application.Resources>
</Application>

更新 1

根据您的解决方案,您需要进行 3 处更改。

  1. 从您的样式 MainTheme.Base 中删除此行。

    <item name="android:windowFullscreen">true</item>
    
  2. 从 MainActivity 中删除这一行 Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);

  3. 添加 Xamarin.Forms.Application.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize); 在 mainactivity 中的 LoadApplication 之后。

更新 2

如果删除android:windowFullscreen混乱的状态栏颜色以及底部栏颜色,我们可以使用自定义渲染。

创建接口IStatusBarPlatformSpecific

public interface IStatusBarPlatformSpecific
    {
        void SetStatusBarColor(Color color);
        void SetBottomBarColor(Color color);
    }

在 android 项目中创建名为 Statusbar

的渲染
[assembly: Dependency(typeof(Statusbar))]
namespace YourAppName.Droid.CustomRender.StatusBar_Color
{
    public class Statusbar : IStatusBarPlatformSpecific
    {
        public Statusbar()
        {
        }
        public void SetStatusBarColor(System.Drawing.Color color)
        {
            CrossCurrentActivity.Current.Activity.Window.SetStatusBarColor(ToAndroidColor(color));
        }   
        public void SetBottomBarColor(System.Drawing.Color color)
        {          
            CrossCurrentActivity.Current.Activity.Window.SetNavigationBarColor(ToAndroidColor(color));
        }

        public static Android.Graphics.Color ToAndroidColor(System.Drawing.Color color)
        {
            return new Android.Graphics.Color(color.ToArgb());
        }
    }
}

现在你可以从你想要的页面调用它OnAppearing像这样。

protected override async void OnAppearing()
        {
            base.OnAppearing();
            if (Device.RuntimePlatform == Device.Android)
            {
                var statusbar = 
                 DependencyService.Get<IStatusBarPlatformSpecific>();
                statusbar.SetStatusBarColor(Color.FromHex("#112330"));
                statusbar.SetBottomBarColor(Color.FromHex("#304E62"));
            }

    }

您现在可以设置状态栏颜色和底部颜色匹配您的 page.Let 我知道这是否适合您。