Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire RefreshView up to our xplat layout workflow #23169

Merged
merged 8 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
@@ -0,0 +1,22 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue23029 : _IssuesUITest
{
public override string Issue => "RefreshView doesn't use correct layout mechanisms";

public Issue23029(TestDevice device) : base(device)
{
}

[Test]
[Category(UITestCategories.RefreshView)]
public void ValidateRefreshViewContentGetsFrameSet()
{
App.WaitForElement("SizeChangedLabel");
}
}
}
45 changes: 45 additions & 0 deletions src/Controls/tests/TestCases/Issues/Issue23029.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue23029">
<!--
Remove RefreshView or comment it out, and you will notice SizeChanged is fired
and if you add RefreshView the SizeChanged will not fire.
-->
<Grid RowDefinitions="Auto,*" x:Name="grid">
<RefreshView Grid.Row="1">
<CollectionView x:Name="CView">

<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1" />
</CollectionView.ItemsLayout>

<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="0, 0, 10, 10">
<Border Padding="20" Stroke="CornflowerBlue" StrokeThickness="1.5" Background="Transparent">
<Border.StrokeShape>
<RoundRectangle CornerRadius="20"/>
</Border.StrokeShape>

<VerticalStackLayout Spacing="10">

<Label Text="{Binding ProgramName}" />

<Label Text="{Binding CourseName}" />

<Label Text="{Binding DueDate}" />

<HorizontalStackLayout Spacing="5">
<Button Text="Download" />
<Button Text="Upload" />
</HorizontalStackLayout>
</VerticalStackLayout>
</Border>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</Grid>
</ContentPage>
53 changes: 53 additions & 0 deletions src/Controls/tests/TestCases/Issues/Issue23029.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.ObjectModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 23029, "RefreshView doesn't use correct layout mechanisms", PlatformAffected.All)]
public partial class Issue23029 : ContentPage
{
public Issue23029()
{
InitializeComponent();
ObservableCollection<AssessmentModel> list = [];
for (int i = 0; i < 100; i++)
{
list.Add(new AssessmentModel()
{
ProgramName = "International Assessment " + i.ToString(),
CourseName = "English " + i.ToString(),
DueDate = DateTime.Now.ToShortDateString()
});
}
CView.ItemsSource = list;

CView.SizeChanged += OnSizeChanged;
}

private void OnSizeChanged(object sender, EventArgs e)
{
if (CView.Frame.Height > 0 && CView.Width > 0 && grid.Children.Count == 1)
{
// Works around a bug with modifying the grid while it's being measured
this.Dispatcher.Dispatch(() =>
{
grid.Children.Insert(0, new Label() { Text = "Size Changed", AutomationId = "SizeChangedLabel" });
});
}

if (sender is CollectionView collectionView && collectionView.ItemsLayout is GridItemsLayout gridItemsLayout)
{
double maxWidthPerItem = 300;
gridItemsLayout.Span = Math.Max(1, (int)(collectionView.Width / maxWidthPerItem));
}
}

public class AssessmentModel
{
public string ProgramName { get; set; } = string.Empty;
public string CourseName { get; set; } = string.Empty;
public string DueDate { get; set; } = string.Empty;
}
}
}
32 changes: 29 additions & 3 deletions src/Core/src/Handlers/RefreshView/RefreshViewHandler.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ protected override RefreshContainer CreatePlatformView()
{
return new RefreshContainer
{
PullDirection = RefreshPullDirection.TopToBottom
PullDirection = RefreshPullDirection.TopToBottom,
Content = new ContentPanel()
};
}

Expand All @@ -35,6 +36,12 @@ protected override void DisconnectHandler(RefreshContainer nativeView)

CompleteRefresh();

if (nativeView.Content is ContentPanel contentPanel)
{
contentPanel.Content = null;
contentPanel.CrossPlatformLayout = null;
}

base.DisconnectHandler(nativeView);
}

Expand Down Expand Up @@ -63,8 +70,27 @@ void UpdateIsRefreshing()

static void UpdateContent(IRefreshViewHandler handler)
{
handler.PlatformView.Content =
handler.VirtualView.Content?.ToPlatform(handler.MauiContext!);
IView content;

if (handler.VirtualView is IContentView cv && cv.PresentedContent is IView view)
{
content = view;
}
else
{
content = handler.VirtualView.Content;
}

var platformContent = content.ToPlatform(handler.MauiContext!);
if (handler.PlatformView.Content is ContentPanel contentPanel)
{
contentPanel.Content = platformContent;
contentPanel.CrossPlatformLayout = (handler.VirtualView as ICrossPlatformLayout);
}
else
{
handler.PlatformView.Content = platformContent;
}
}

static void UpdateRefreshColor(IRefreshViewHandler handler)
Expand Down
32 changes: 29 additions & 3 deletions src/Core/src/Handlers/RefreshView/RefreshViewHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,21 @@ public partial class RefreshViewHandler : ViewHandler<IRefreshView, MauiRefreshV

protected override MauiRefreshView CreatePlatformView()
{
return new MauiRefreshView();
return new MauiRefreshView
{
CrossPlatformLayout = VirtualView as ICrossPlatformLayout
};
}

public override void SetVirtualView(IView view)
{
base.SetVirtualView(view);

_ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class.");
_ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class.");

PlatformView.View = view;
PlatformView.CrossPlatformLayout = VirtualView as ICrossPlatformLayout;
}

protected override void ConnectHandler(MauiRefreshView platformView)
Expand All @@ -26,6 +40,8 @@ protected override void ConnectHandler(MauiRefreshView platformView)
protected override void DisconnectHandler(MauiRefreshView platformView)
{
_proxy.Disconnect(platformView);
platformView.CrossPlatformLayout = null;
platformView.RemoveFromSuperview();

base.DisconnectHandler(platformView);
}
Expand All @@ -50,8 +66,18 @@ static void UpdateIsRefreshing(IRefreshViewHandler handler)
handler.PlatformView.IsRefreshing = handler.VirtualView.IsRefreshing;
}

static void UpdateContent(IRefreshViewHandler handler) =>
handler.PlatformView.UpdateContent(handler.VirtualView.Content, handler.MauiContext);
static void UpdateContent(IRefreshViewHandler handler)
{
if (handler.VirtualView is IContentView cv && cv.PresentedContent is IView view)
{
handler.PlatformView.UpdateContent(view, handler.MauiContext);
}
else
{
handler.PlatformView.UpdateContent(handler.VirtualView.Content, handler.MauiContext);
}

}

static void UpdateRefreshColor(IRefreshViewHandler handler)
{
Expand Down
33 changes: 5 additions & 28 deletions src/Core/src/Platform/iOS/MauiRefreshView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Microsoft.Maui.Platform
{
public class MauiRefreshView : UIView, IUIViewLifeCycleEvents
public class MauiRefreshView : MauiView
{
bool _isRefreshing;
nfloat _originalY;
Expand Down Expand Up @@ -54,12 +54,14 @@ public bool IsRefreshing

public void UpdateContent(IView? content, IMauiContext? mauiContext)
{
if (_refreshControlParent != null)
if (_refreshControlParent is not null)
{
TryRemoveRefresh(_refreshControlParent);
}

_contentView?.RemoveFromSuperview();

if (content != null && mauiContext != null)
if (content is not null && mauiContext is not null)
{
_contentView = content.ToPlatform(mauiContext);
AddSubview(_contentView);
Expand Down Expand Up @@ -166,17 +168,6 @@ bool TryInsertRefresh(UIView view, int index = 0)
return false;
}

public override CGRect Bounds
{
get => base.Bounds;
set
{
base.Bounds = value;
if (_contentView != null)
_contentView.Frame = value;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was most likely here to workaround the fact that we didn't have the layout path setup correctly.

It looks like the original addition of this didn't add tests
#14302

So, it'd be good to test through those closed issues

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran the sample here and it looks good still

image

}
}

public void UpdateIsEnabled(bool isRefreshViewEnabled)
{
_refreshControl.Enabled = isRefreshViewEnabled;
Expand All @@ -198,19 +189,5 @@ public void UpdateIsEnabled(bool isRefreshViewEnabled)
bool CanUseRefreshControlProperty() =>
this.GetNavigationController()?.NavigationBar?.PrefersLargeTitles ?? true;
#pragma warning restore CA1416

[UnconditionalSuppressMessage("Memory", "MEM0002", Justification = IUIViewLifeCycleEvents.UnconditionalSuppressMessage)]
EventHandler? _movedToWindow;
event EventHandler IUIViewLifeCycleEvents.MovedToWindow
{
add => _movedToWindow += value;
remove => _movedToWindow -= value;
}

public override void MovedToWindow()
{
base.MovedToWindow();
_movedToWindow?.Invoke(this, EventArgs.Empty);
}
}
}
4 changes: 1 addition & 3 deletions src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Microsoft.Maui.Platform.MauiScrollView.MauiScrollView() -> void
Microsoft.Maui.SoftInputExtensions
override Microsoft.Maui.Handlers.ButtonHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.ContentViewHandler.DisconnectHandler(Microsoft.Maui.Platform.ContentView! platformView) -> void
override Microsoft.Maui.Handlers.RefreshViewHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void
override Microsoft.Maui.Handlers.ScrollViewHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.SwipeItemButton.Frame.get -> CoreGraphics.CGRect
override Microsoft.Maui.Handlers.SwipeItemButton.Frame.set -> void
Expand All @@ -64,9 +65,6 @@ override Microsoft.Maui.Platform.MauiBoxView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiCheckBox.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiLabel.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiPageControl.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiRefreshView.Bounds.get -> CoreGraphics.CGRect
override Microsoft.Maui.Platform.MauiRefreshView.Bounds.set -> void
override Microsoft.Maui.Platform.MauiRefreshView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiScrollView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiScrollView.ScrollRectToVisible(CoreGraphics.CGRect rect, bool animated) -> void
override Microsoft.Maui.Platform.MauiSearchBar.MovedToWindow() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Microsoft.Maui.SoftInputExtensions
override Microsoft.Maui.Handlers.BorderHandler.PlatformArrange(Microsoft.Maui.Graphics.Rect rect) -> void
override Microsoft.Maui.Handlers.ButtonHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.ContentViewHandler.DisconnectHandler(Microsoft.Maui.Platform.ContentView! platformView) -> void
override Microsoft.Maui.Handlers.RefreshViewHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void
override Microsoft.Maui.Handlers.ScrollViewHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.SwipeItemButton.Frame.get -> CoreGraphics.CGRect
override Microsoft.Maui.Handlers.SwipeItemButton.Frame.set -> void
Expand All @@ -67,9 +68,6 @@ override Microsoft.Maui.Platform.MauiBoxView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiCheckBox.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiLabel.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiPageControl.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiRefreshView.Bounds.get -> CoreGraphics.CGRect
override Microsoft.Maui.Platform.MauiRefreshView.Bounds.set -> void
override Microsoft.Maui.Platform.MauiRefreshView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiScrollView.MovedToWindow() -> void
override Microsoft.Maui.Platform.MauiScrollView.ScrollRectToVisible(CoreGraphics.CGRect rect, bool animated) -> void
override Microsoft.Maui.Platform.MauiSearchBar.MovedToWindow() -> void
Expand Down