Reputation: 1568
I have the following xamarin layout schemma:
<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 behavior is surprisingly as I want(that's a chat layout, so top bar has pic and username which I want to be visible all time), but android behavior is up scrolling the whole page and keeping only Entry and bottom of ScrollView visible, that is almost what I need, but Top Grid is disappearing. Only Srollview and the Bottom grid musts scroll.
How can I achieve this?
EDIT 1
Sample project:
https://wetransfer.com/downloads/46b455cb7148189a0d1f84affa77b7e120210428144025/02b001
Upvotes: 2
Views: 1523
Reputation: 1959
Can you try like this.
The basic Layout structre will be like this.
<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>
On your PCL, Create KeyboardView
public class KeyboardView : Grid { }
On ios Create 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;
}
}
}
}
For Android add this in 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>
UPDATE 1
From Your solution, You need to make 3 Changes.
Remove this line from MainTheme.Base in your style.
<item name="android:windowFullscreen">true</item>
Remove this line from MainActivity Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);
Add
Xamarin.Forms.Application.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
After LoadApplication in mainactivity.
UPDATE 2
If removing android:windowFullscreen
messed status bar color as well as bottom bar color, We can make use of custom render.
Create an Interface IStatusBarPlatformSpecific
public interface IStatusBarPlatformSpecific
{
void SetStatusBarColor(Color color);
void SetBottomBarColor(Color color);
}
In android project create render named 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());
}
}
}
Now you can call it from your desired pages OnAppearing
Like this.
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"));
}
}
You can now set the status bar color and bottom color matching to your page.Let me know if this worked for you.
Upvotes: 1