Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using AndroidX.Core.View;
using AndroidX.Fragment.App;
using Google.Android.Material.AppBar;
using Microsoft.Maui.Platform;
using AndroidAnimation = Android.Views.Animations.Animation;
using AnimationSet = Android.Views.Animations.AnimationSet;
using AToolbar = AndroidX.AppCompat.Widget.Toolbar;
Expand Down Expand Up @@ -66,7 +67,7 @@ void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance)
IShellToolbarAppearanceTracker _appearanceTracker;
Page _page;
IPlatformViewHandler _viewhandler;
AView _root;
CoordinatorLayout _root;
ShellPageContainer _shellPageContainer;
ShellContent _shellContent;
AToolbar _toolbar;
Expand Down Expand Up @@ -135,6 +136,8 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,

_root = inflater.Inflate(Controls.Resource.Layout.shellcontent, null).JavaCast<CoordinatorLayout>();

MauiWindowInsetListener.SetupViewWithLocalListener(_root);

var shellContentMauiContext = _shellContext.Shell.Handler.MauiContext.MakeScoped(layoutInflater: inflater, fragmentManager: ChildFragmentManager);

Maui.IElement parentElement = (_shellContent as Maui.IElement) ?? _page;
Expand All @@ -143,9 +146,6 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
_toolbar = (AToolbar)shellToolbar.ToPlatform(shellContentMauiContext);

var appBar = _root.FindViewById<AppBarLayout>(Resource.Id.shellcontent_appbar);

GlobalWindowInsetListenerExtensions.TrySetGlobalWindowInsetListener(_root, this.Context);

appBar.AddView(_toolbar);
_viewhandler = _page.ToHandler(shellContentMauiContext);

Expand Down Expand Up @@ -183,6 +183,12 @@ void Destroy()
// to avoid the navigation `TaskCompletionSource` to be stuck forever.
AnimationFinished?.Invoke(this, EventArgs.Empty);

// Clean up the coordinator layout and local listener first
if (_root is not null)
{
MauiWindowInsetListener.RemoveViewWithLocalListener(_root);
}

(_shellContext?.Shell as IShellController)?.RemoveAppearanceObserver(this);

if (_shellContent != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void OnFlyoutStateChanging(object sender, AndroidX.DrawerLayout.Widget.DrawerLay
// - Keep this minimal.
// - Will be replaced by the planned comprehensive window insets solution.
// - Do not extend; add new logic to the forthcoming implementation instead.
internal class WindowsListener : Java.Lang.Object, IOnApplyWindowInsetsListener
internal class WindowsListener : MauiWindowInsetListener, IOnApplyWindowInsetsListener
{
private WeakReference<ImageView> _bgImageRef;
private WeakReference<AView> _flyoutViewRef;
Expand All @@ -100,10 +100,10 @@ public AView FlyoutView

return null;
}
set
{
set
{
_flyoutViewRef = new WeakReference<AView>(value);
}
}
}
public AView FooterView
{
Expand All @@ -114,62 +114,68 @@ public AView FooterView

return null;
}
set
{
set
{
_footerViewRef = new WeakReference<AView>(value);
}
}
}

public WindowsListener(ImageView bgImage)
{
_bgImageRef = new WeakReference<ImageView>(bgImage);
}

public WindowInsetsCompat OnApplyWindowInsets(AView v, WindowInsetsCompat insets)
public override WindowInsetsCompat OnApplyWindowInsets(AView v, WindowInsetsCompat insets)
{
if (insets == null || v == null)
return insets;

// The flyout overlaps the status bar so we don't really care about insetting it
var systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars());
var displayCutout = insets.GetInsets(WindowInsetsCompat.Type.DisplayCutout());
var topInset = Math.Max(systemBars?.Top ?? 0, displayCutout?.Top ?? 0);
var bottomInset = Math.Max(systemBars?.Bottom ?? 0, displayCutout?.Bottom ?? 0);
var appbarLayout = v.FindDescendantView<AppBarLayout>((v) => true);
if (v is CoordinatorLayout)
{
// The flyout overlaps the status bar so we don't really care about insetting it
var systemBars = insets.GetInsets(WindowInsetsCompat.Type.SystemBars());
var displayCutout = insets.GetInsets(WindowInsetsCompat.Type.DisplayCutout());
var topInset = Math.Max(systemBars?.Top ?? 0, displayCutout?.Top ?? 0);
var bottomInset = Math.Max(systemBars?.Bottom ?? 0, displayCutout?.Bottom ?? 0);
var appbarLayout = v.FindDescendantView<AppBarLayout>((v) => true);

int flyoutViewBottomInset = 0;
int flyoutViewBottomInset = 0;

if (FooterView is not null)
{
v.SetPadding(0, 0, 0, bottomInset);
flyoutViewBottomInset = 0;
}
else
{
flyoutViewBottomInset = bottomInset;
v.SetPadding(0, 0, 0, 0);
}
if (FooterView is not null)
{
v.SetPadding(0, 0, 0, bottomInset);
flyoutViewBottomInset = 0;
}
else
{
flyoutViewBottomInset = bottomInset;
v.SetPadding(0, 0, 0, 0);
}

if (appbarLayout.MeasuredHeight > 0)
{
FlyoutView?.SetPadding(0, 0, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, topInset, 0, 0);
}
else
{
FlyoutView?.SetPadding(0, topInset, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, 0, 0, 0);
}
if (appbarLayout.MeasuredHeight > 0)
{
FlyoutView?.SetPadding(0, 0, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, topInset, 0, 0);
}
else
{
FlyoutView?.SetPadding(0, topInset, 0, flyoutViewBottomInset);
appbarLayout?.SetPadding(0, 0, 0, 0);
}

if (_bgImageRef != null && _bgImageRef.TryGetTarget(out var bgImage) && bgImage != null)
{
bgImage.SetPadding(0, topInset, 0, bottomInset);
if (_bgImageRef != null && _bgImageRef.TryGetTarget(out var bgImage) && bgImage != null)
{
bgImage.SetPadding(0, topInset, 0, bottomInset);
}

return WindowInsetsCompat.Consumed;
}

return WindowInsetsCompat.Consumed;

return base.OnApplyWindowInsets(v, insets);
}
}

protected virtual void LoadView(IShellContext shellContext)
{
var context = shellContext.AndroidContext;
Expand Down Expand Up @@ -202,7 +208,7 @@ protected virtual void LoadView(IShellContext shellContext)
};

_windowsListener = new WindowsListener(_bgImage);
ViewCompat.SetOnApplyWindowInsetsListener(coordinator, _windowsListener);
MauiWindowInsetListener.SetupViewWithLocalListener(coordinator, _windowsListener);

UpdateFlyoutHeaderBehavior();
_shellContext.Shell.PropertyChanged += OnShellPropertyChanged;
Expand Down Expand Up @@ -718,6 +724,12 @@ public void OnOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)

internal void Disconnect()
{

if (_rootView is CoordinatorLayout coordinator)
{
MauiWindowInsetListener.RemoveViewWithLocalListener(coordinator);
}

if (_shellContext?.Shell != null)
_shellContext.Shell.PropertyChanged -= OnShellPropertyChanged;

Expand All @@ -726,14 +738,12 @@ internal void Disconnect()

_flyoutHeader = null;

if (_footerView != null)
_footerView.View = null;
_footerView?.View = null;

_headerView?.Disconnect();
DisconnectRecyclerView();

if (_contentView != null)
_contentView.View = null;
_contentView?.View = null;
}

protected override void Dispose(bool disposing)
Expand Down Expand Up @@ -764,8 +774,7 @@ protected override void Dispose(bool disposing)
if (_headerView != null)
_headerView.LayoutChange -= OnHeaderViewLayoutChange;

if (_contentView != null)
_contentView.View = null;
_contentView?.View = null;

_flyoutContentView?.Dispose();
_headerView?.Dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
using AndroidX.Fragment.App;
using AndroidX.ViewPager.Widget;
using AndroidX.ViewPager2.Widget;
using Google.Android.Material.AppBar;
using Google.Android.Material.Tabs;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Platform;
using AToolbar = AndroidX.AppCompat.Widget.Toolbar;
using AView = Android.Views.View;

Expand Down Expand Up @@ -66,7 +68,7 @@ void AView.IOnClickListener.OnClick(AView v)
#endregion IOnClickListener

readonly IShellContext _shellContext;
AView _rootView;
CoordinatorLayout _rootView;
bool _selecting;
TabLayout _tablayout;
IShellTabLayoutAppearanceTracker _tabLayoutAppearanceTracker;
Expand Down Expand Up @@ -101,7 +103,9 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
var context = Context;
var root = PlatformInterop.CreateShellCoordinatorLayout(context);
var appbar = PlatformInterop.CreateShellAppBar(context, Resource.Attribute.appBarLayoutStyle, root);
GlobalWindowInsetListenerExtensions.TrySetGlobalWindowInsetListener(root, this.Context);

MauiWindowInsetListener.SetupViewWithLocalListener(root);

int actionBarHeight = context.GetActionBarHeight();

var shellToolbar = new Toolbar(shellSection);
Expand Down Expand Up @@ -194,6 +198,12 @@ void Destroy()
{
if (_rootView != null)
{
// Clean up the coordinator layout and local listener first
if (_rootView is not null)
{
MauiWindowInsetListener.RemoveViewWithLocalListener(_rootView);
}

UnhookEvents();

_shellContext?.Shell?.Toolbar?.Handler?.DisconnectHandler();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,7 @@ protected virtual async void UpdateLeftBarButtonItem(Context context, AToolbar t
defaultDrawerArrowDrawable = true;
}

if (icon != null)
icon.Progress = (CanNavigateBack) ? 1 : 0;
icon?.Progress = (CanNavigateBack) ? 1 : 0;

if (command != null || CanNavigateBack)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
namespace Microsoft.Maui.Controls.Handlers.Items
{

public class MauiRecyclerView<TItemsView, TAdapter, TItemsViewSource> : RecyclerView, IMauiRecyclerView<TItemsView>
public class MauiRecyclerView<TItemsView, TAdapter, TItemsViewSource> : RecyclerView, IMauiRecyclerView<TItemsView>, IMauiRecyclerView
where TItemsView : ItemsView
where TAdapter : ItemsViewAdapter<TItemsView, TItemsViewSource>
where TItemsViewSource : IItemsViewSource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
using Android.Views;
using Android.Views.Animations;
using AndroidX.Activity;
using AndroidX.Core.View;
using AndroidX.Fragment.App;
using Microsoft.Maui.LifecycleEvents;
using AAnimation = Android.Views.Animations.Animation;
using AColor = Android.Graphics.Color;
using AView = Android.Views.View;
using AndroidX.Core.View;

namespace Microsoft.Maui.Controls.Platform
{
Expand Down Expand Up @@ -206,7 +206,6 @@ internal class ModalFragment : DialogFragment
Page _modal;
IMauiContext _mauiWindowContext;
NavigationRootManager? _navigationRootManager;
GlobalWindowInsetListener? _modalInsetListener;
static readonly ColorDrawable TransparentColorDrawable = new(AColor.Transparent);
bool _pendingAnimation = true;

Expand Down Expand Up @@ -320,15 +319,6 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup? container
var rootView = _navigationRootManager?.RootView ??
throw new InvalidOperationException("Root view not initialized");

var context = rootView.Context ?? inflater.Context;
if (context is not null)
{
// Modal pages get their own separate GlobalWindowInsetListener instance
// This prevents cross-contamination with the main window's inset tracking
_modalInsetListener = new GlobalWindowInsetListener();
ViewCompat.SetOnApplyWindowInsetsListener(rootView, _modalInsetListener);
}

if (IsAnimated)
{
_ = new GenericGlobalLayoutListener((listener, view) =>
Expand Down Expand Up @@ -383,20 +373,6 @@ public override void OnDismiss(IDialogInterface dialog)
_modal.Toolbar.Handler = null;
}

// Clean up the modal's separate GlobalWindowInsetListener
if (_modalInsetListener is not null)
{
_modalInsetListener.ResetAllViews();
_modalInsetListener.Dispose();
_modalInsetListener = null;
}

var rootView = _navigationRootManager?.RootView;
if (rootView is not null)
{
ViewCompat.SetOnApplyWindowInsetsListener(rootView, null);
}

_modal.Handler = null;
_modal = null!;
_mauiWindowContext = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ public async Task ShouldGrow()
var screenHeightConstraint = 600;

var label = new Label() { Text = "Text inside a ScrollView" };
var childLayout = new VerticalStackLayout { label };
var scrollView = new ScrollView() { VerticalOptions = LayoutOptions.Fill, Content = childLayout };
var parentLayout = new Grid { scrollView };
var childLayout = new VerticalStackLayout { SafeAreaEdges = SafeAreaEdges.None, Children = { label } };
var scrollView = new ScrollView() { SafeAreaEdges = SafeAreaEdges.None, VerticalOptions = LayoutOptions.Fill, Content = childLayout };
var parentLayout = new Grid { SafeAreaEdges = SafeAreaEdges.None, Children = { scrollView } };

var expectedHeight = 100;
parentLayout.HeightRequest = expectedHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/dotnet/2021/maui/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
SafeAreaEdges="Container"
x:Class=" Maui.Controls.Sample.CollectionViewGalleries.HeaderFooterGalleries.HeaderFooterView">
<ContentPage.Content>

Expand Down
8 changes: 8 additions & 0 deletions src/Core/src/Core/IMauiRecyclerView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Collections.Generic;

namespace Microsoft.Maui
{
internal interface IMauiRecyclerView
{
}
}
Loading
Loading