软键盘打开时如何防止特定的 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 处更改。
从您的样式 MainTheme.Base 中删除此行。
<item name="android:windowFullscreen">true</item>
从 MainActivity 中删除这一行 Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);
添加
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 我知道这是否适合您。
我有以下 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 处更改。
从您的样式 MainTheme.Base 中删除此行。
<item name="android:windowFullscreen">true</item>
从 MainActivity 中删除这一行
Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);
添加
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 我知道这是否适合您。