2

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

Éder Rocha
  • 1,538
  • 11
  • 29
  • If you are designing a chat page, why dont you use listview or collectionview for your chat instead of putting inside scrollview? – Anand Apr 27 '21 at 16:56
  • @Anand there is a CollectionView inside the ScrollView, it was proposital for avoiding soft keyboard overlapping focused views in iOS. But even if I take off scrollview, android has same behavior, it's why I didn't mentioned the collection view. – Éder Rocha Apr 27 '21 at 17:04

1 Answers1

1

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.

  1. Remove this line from MainTheme.Base in your style.

    <item name="android:windowFullscreen">true</item>
    
  2. Remove this line from MainActivity Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);

  3. 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.

Anand
  • 1,866
  • 3
  • 26
  • 49
  • Thank you for your attention. I just made those changes, it was good since now I can take off that ScrollView and make things lighter and working properly(I mean, the keyboard overlapping issue on ios). But the original problem of this question is presented yet. Same behavior, it keeps kicking the top grid to out from screen. – Éder Rocha Apr 27 '21 at 18:30
  • 1
    My project doesn't have app.xaml so I added Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize); at MainActivity.cs, it makes same work, right? – Éder Rocha Apr 27 '21 at 19:37
  • I just noticed that CollectionView is up scrolling some lines also, so I have to scroll down when keyboard is open. – Éder Rocha Apr 27 '21 at 19:55
  • @ÉderRocha Can you provide me a sample project? So that I can test from my end – Anand Apr 28 '21 at 12:31
  • Sure, this is a cleaned version, only with chat page https://wetransfer.com/downloads/46b455cb7148189a0d1f84affa77b7e120210428144025/02b001 – Éder Rocha Apr 28 '21 at 14:42
  • Hi Iam not able to run the given sample. Getting exception like "System.Collections.Generic.KeyNotFoundException: 'The given key 'userid' was not present in the dictionary.'" – Anand Apr 29 '21 at 05:31
  • sorry, since I already had login data in my device this error wasn't presented, fix this by changing line 15 of file Msg.cs in PCL, change private int MeuID = Convert.ToInt32((App.Current.Properties["userid"] as string)); BY MeuID = 5; – Éder Rocha Apr 29 '21 at 11:28
  • 1
    @ÉderRocha Ok let me try – Anand Apr 29 '21 at 13:08
  • Unfortunately no! – Éder Rocha Apr 29 '21 at 18:41
  • are you trying yet or have dismissed it? – Éder Rocha Apr 29 '21 at 19:25
  • 1
    @ÉderRocha Can you try my updated answer? – Anand Apr 29 '21 at 20:15
  • 1
    With your last update it worked as expected. Thanks for your time and attention. – Éder Rocha Apr 30 '21 at 13:05
  • @ÉderRocha Glad it helped. – Anand Apr 30 '21 at 17:28
  • one more question, is there any way of letting only Chat Page as no fullscreen mode? – Éder Rocha Apr 30 '21 at 20:36
  • @ÉderRocha Is it because you want to control status bar color and bottom navigation bar color? – Anand May 01 '21 at 13:37
  • 1
    @ÉderRocha I forgot to tell you. You need to install Current activty plugin also in your android project. Ref : https://github.com/jamesmontemagno/CurrentActivityPlugin – Anand May 02 '21 at 15:33
  • I tried this approach, but it's causing the view to bounce up and then back in iOS when ever OnKeyboardShow() is executed, Can someone help please? – Mars Jul 22 '22 at 11:34