Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 65e22f0

Browse files
pictosPureWeen
andauthored
Fix flyout render quirks (#12129)
* Fix UWP and wrong flyout render logic * Fixed FlyoutItemVisibleWorksForMenuItemsAddedAsShellItem unittest * fixed grouping in Flyout * added handle for GetIsVisible for MenuItem * fixed unit test for FlyoutGroupsNumbersForFlyoutDisplayOptionsAsMultipleItems * - only increment when needed * - fix test * - fix names * - fix wrong disable behavior * - generate less noise if flyout hasn't changed Co-authored-by: Shane Neuville <[email protected]>
1 parent e8d06f3 commit 65e22f0

File tree

12 files changed

+457
-128
lines changed

12 files changed

+457
-128
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using NUnit.Framework;
7+
8+
namespace Xamarin.Forms.Core.UnitTests
9+
{
10+
[TestFixture]
11+
public class ShellFlyoutItemGroupTests : ShellTestBase
12+
{
13+
[Test]
14+
public void FlyoutCreatesCorrectNumberOfGroupsForAsMultipleItems()
15+
{
16+
var shell = new Shell();
17+
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
18+
var shellItem2 = new ShellItem();
19+
20+
shellItem.Items.Add(CreateShellSection());
21+
shellItem.Items.Add(CreateShellSection());
22+
shellItem2.Items.Add(CreateShellContent());
23+
shellItem2.Items.Add(CreateShellSection());
24+
25+
shell.Items.Add(shellItem);
26+
shell.Items.Add(shellItem2);
27+
IShellController shellController = shell;
28+
var groups = shellController.GenerateFlyoutGrouping();
29+
30+
Assert.AreEqual(groups.Count, 2);
31+
Assert.AreEqual(groups[0].Count, 2);
32+
Assert.AreEqual(groups[1].Count, 1);
33+
}
34+
35+
[Test]
36+
public void FlyoutCreatesCorrectNumberOfGroupsForNestedAsMultipleItems()
37+
{
38+
var shell = new Shell();
39+
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
40+
var shellItem2 = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
41+
42+
shellItem.Items.Add(CreateShellSection());
43+
shellItem.Items.Add(CreateShellSection());
44+
45+
shellItem2.Items.Add(CreateShellContent());
46+
shellItem2.Items.Add(CreateShellSection());
47+
48+
shell.Items.Add(shellItem);
49+
shell.Items.Add(shellItem2);
50+
51+
IShellController shellController = shell;
52+
var groups = shellController.GenerateFlyoutGrouping();
53+
54+
Assert.AreEqual(2, groups.Count);
55+
Assert.AreEqual(groups[0].Count, 2);
56+
Assert.AreEqual(groups[1].Count, 2);
57+
}
58+
59+
[Test]
60+
public void FlyoutCreatesCorrectNumberOfGroupsForAsSingleItem()
61+
{
62+
var shell = new Shell();
63+
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsSingleItem, };
64+
var shellItem2 = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsSingleItem, };
65+
66+
shellItem.Items.Add(CreateShellSection());
67+
shellItem.Items.Add(CreateShellSection());
68+
shellItem2.Items.Add(CreateShellContent());
69+
shellItem2.Items.Add(CreateShellSection());
70+
71+
72+
shell.Items.Add(shellItem);
73+
shell.Items.Add(shellItem2);
74+
IShellController shellController = shell;
75+
var groups = shellController.GenerateFlyoutGrouping();
76+
77+
Assert.AreEqual(groups.Count, 1);
78+
Assert.AreEqual(groups[0].Count, 2);
79+
}
80+
81+
[Test]
82+
public void MenuItemGeneratesForShellContent()
83+
{
84+
var shell = new TestShell();
85+
86+
var shellContent = CreateShellContent();
87+
shellContent.MenuItems.Add(new MenuItem());
88+
shell.Items.Add(shellContent);
89+
90+
IShellController shellController = (IShellController)shell;
91+
var groups = shellController.GenerateFlyoutGrouping();
92+
Assert.AreEqual(groups.SelectMany(x => x.OfType<IMenuItemController>()).Count(), 1);
93+
}
94+
95+
96+
[Test]
97+
public void MenuItemGeneratesForShellSection()
98+
{
99+
var shell = new TestShell();
100+
101+
var shellSection = CreateShellSection<Tab>();
102+
shellSection.CurrentItem.MenuItems.Add(new MenuItem());
103+
shellSection.FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems;
104+
shell.Items.Add(shellSection);
105+
106+
IShellController shellController = (IShellController)shell;
107+
var groups = shellController.GenerateFlyoutGrouping();
108+
Assert.AreEqual(1, groups.SelectMany(x => x.OfType<IMenuItemController>()).Count());
109+
}
110+
111+
112+
[Test]
113+
public void FlyoutItemVisibleWorksForMenuItemsAddedAsShellItem()
114+
{
115+
var shell = new TestShell();
116+
var item = new MenuShellItem(CreateNonVisibleMenuItem());
117+
shell.Items.Add(item);
118+
119+
var itemsAreEquals = item.Equals(shell.Items[0]);
120+
Assert.IsTrue(itemsAreEquals);
121+
122+
IShellController shellController = (IShellController)shell;
123+
var groups = shellController.GenerateFlyoutGrouping();
124+
125+
var r = groups.SelectMany(x => x.OfType<IMenuItemController>());
126+
127+
Assert.AreEqual(r.Count(), 0);
128+
}
129+
130+
[Test]
131+
public void FlyoutItemVisibleWorksForMenuItemsAddedAsTab()
132+
{
133+
var shell = new TestShell();
134+
135+
var shellSection = CreateShellSection<Tab>();
136+
shellSection.Items[0].MenuItems.Add(CreateNonVisibleMenuItem());
137+
shell.Items.Add(shellSection);
138+
139+
IShellController shellController = (IShellController)shell;
140+
var groups = shellController.GenerateFlyoutGrouping();
141+
Assert.AreEqual(groups.SelectMany(x => x.OfType<IMenuItemController>()).Count(), 0);
142+
}
143+
144+
[Test]
145+
public void FlyoutItemVisibleWorksForMenuItemsAddedAsShellContent()
146+
{
147+
var shell = new TestShell();
148+
149+
var shellContent = CreateShellContent();
150+
shellContent.MenuItems.Add(CreateNonVisibleMenuItem());
151+
shell.Items.Add(shellContent);
152+
153+
IShellController shellController = (IShellController)shell;
154+
var groups = shellController.GenerateFlyoutGrouping();
155+
Assert.AreEqual(groups.SelectMany(x => x.OfType<IMenuItemController>()).Count(), 0);
156+
}
157+
158+
[Test]
159+
public void FlyoutItemVisibleWorksForMenuItemsFlyoutItemAsMultipleItems()
160+
{
161+
var shell = new TestShell();
162+
163+
var flyoutItem = CreateShellItem<FlyoutItem>();
164+
flyoutItem.FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems;
165+
flyoutItem.CurrentItem.CurrentItem.MenuItems.Add(CreateNonVisibleMenuItem());
166+
shell.Items.Add(flyoutItem);
167+
168+
169+
IShellController shellController = (IShellController)shell;
170+
var groups = shellController.GenerateFlyoutGrouping();
171+
Assert.AreEqual(groups.SelectMany(x => x.OfType<IMenuItemController>()).Count(), 0);
172+
}
173+
174+
[Test]
175+
public void FlyoutItemVisibleWorksForMenuItemsTabAsMultipleItems()
176+
{
177+
var shell = new TestShell();
178+
179+
var flyoutItem = CreateShellItem<FlyoutItem>();
180+
flyoutItem.FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems;
181+
flyoutItem.CurrentItem.FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems;
182+
flyoutItem.CurrentItem.CurrentItem.MenuItems.Add(CreateNonVisibleMenuItem());
183+
shell.Items.Add(flyoutItem);
184+
185+
IShellController shellController = (IShellController)shell;
186+
var groups = shellController.GenerateFlyoutGrouping();
187+
Assert.AreEqual(0, groups.SelectMany(x => x.OfType<IMenuItemController>()).Count());
188+
}
189+
190+
[Test]
191+
public void FlyoutItemNotVisibleWhenShellContentSetToNotVisible()
192+
{
193+
var shell = new TestShell();
194+
var shellSection = CreateShellSection();
195+
shellSection.FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems;
196+
shellSection.Items.Add(CreateShellContent());
197+
shellSection.Items[0].IsVisible = false;
198+
shell.Items.Add(shellSection);
199+
200+
IShellController shellController = (IShellController)shell;
201+
var groups = shellController.GenerateFlyoutGrouping();
202+
Assert.AreEqual(1, groups.Count);
203+
Assert.AreEqual(1, groups[0].Count);
204+
}
205+
206+
[Test]
207+
public void ReturnTheSameGroupingInstanceIfStructureHasntChanged()
208+
{
209+
var shell = new TestShell();
210+
211+
shell.Items.Add(CreateShellItem<FlyoutItem>());
212+
213+
var flyoutItems = shell.Controller.GenerateFlyoutGrouping();
214+
var flyoutItems2 = shell.Controller.GenerateFlyoutGrouping();
215+
216+
Assert.AreSame(flyoutItems, flyoutItems2);
217+
218+
shell.Items.Add(CreateShellItem<FlyoutItem>());
219+
flyoutItems2 = shell.Controller.GenerateFlyoutGrouping();
220+
221+
Assert.AreNotSame(flyoutItems, flyoutItems2);
222+
}
223+
224+
MenuItem CreateNonVisibleMenuItem()
225+
{
226+
MenuItem item = new MenuItem();
227+
FlyoutItem.SetIsVisible(item, false);
228+
return item;
229+
}
230+
}
231+
}

Xamarin.Forms.Core.UnitTests/ShellTestBase.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ protected ShellContent CreateShellContent(TemplatedPage page = null, bool asImpl
216216
content.Route = shellContentRoute;
217217
}
218218
else if (asImplicit)
219-
content = (ShellContent)page;
219+
{
220+
content = (ShellContent)(page ?? new ContentPage());
221+
}
220222
else
221223
{
222224
if (templated)
@@ -289,6 +291,8 @@ public class TestShell : Shell
289291
public ShellNavigatedEventArgs LastShellNavigatedEventArgs;
290292
public ShellNavigatingEventArgs LastShellNavigatingEventArgs;
291293

294+
public IShellController Controller => this;
295+
292296
public TestShell()
293297
{
294298
this.Navigated += (_, __) => NavigatedCount++;

Xamarin.Forms.Core.UnitTests/ShellTests.cs

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -761,83 +761,7 @@ public async Task FlyoutNavigateToImplicitContentPage()
761761

762762
}
763763

764-
[Test]
765-
public void FlyoutGroupsNumbersForDifferentFlyoutDisplayOptions()
766-
{
767-
var shell = new Shell();
768-
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
769-
var shellItem2 = new ShellItem();
770-
var shellSection1 = CreateShellSection(new ContentPage());
771-
var shellSection2 = CreateShellSection(new ContentPage());
772-
var shellSection3 = CreateShellSection(new ContentPage(), asImplicit: true);
773-
var shellSection4 = CreateShellSection(new ContentPage());
774-
775-
shellItem.Items.Add(shellSection1);
776-
shellItem.Items.Add(shellSection2);
777-
shellItem2.Items.Add(shellSection3);
778-
shellItem2.Items.Add(shellSection4);
779-
780-
shell.Items.Add(shellItem);
781-
shell.Items.Add(shellItem2);
782-
IShellController shellController = (IShellController)shell;
783-
var groups = shellController.GenerateFlyoutGrouping();
784-
785-
Assert.AreEqual(groups.Count, 2);
786-
Assert.AreEqual(groups[0].Count, 2);
787-
Assert.AreEqual(groups[1].Count, 1);
788-
}
789-
790-
[Test]
791-
public void FlyoutGroupsNumbersForFlyoutDisplayOptionsAsMultipleItems()
792-
{
793-
var shell = new Shell();
794-
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
795-
var shellItem2 = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems, };
796-
var shellSection1 = CreateShellSection(new ContentPage());
797-
var shellSection2 = CreateShellSection(new ContentPage());
798-
var shellSection3 = CreateShellSection(new ContentPage(), asImplicit: true);
799-
var shellSection4 = CreateShellSection(new ContentPage());
800-
801-
shellItem.Items.Add(shellSection1);
802-
shellItem.Items.Add(shellSection2);
803-
shellItem2.Items.Add(shellSection3);
804-
shellItem2.Items.Add(shellSection4);
805-
806-
shell.Items.Add(shellItem);
807-
shell.Items.Add(shellItem2);
808-
IShellController shellController = (IShellController)shell;
809-
var groups = shellController.GenerateFlyoutGrouping();
810-
811-
Assert.AreEqual(groups.Count, 2);
812-
Assert.AreEqual(groups[0].Count, 2);
813-
Assert.AreEqual(groups[1].Count, 2);
814-
}
815-
816-
[Test]
817-
public void FlyoutGroupsNumbersForFlyoutDisplayOptionsAsSingleItems()
818-
{
819-
var shell = new Shell();
820-
var shellItem = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsSingleItem, };
821-
var shellItem2 = new ShellItem() { FlyoutDisplayOptions = FlyoutDisplayOptions.AsSingleItem, };
822-
var shellSection1 = CreateShellSection(new ContentPage());
823-
var shellSection2 = CreateShellSection(new ContentPage());
824-
var shellSection3 = CreateShellSection(new ContentPage(), asImplicit: true);
825-
var shellSection4 = CreateShellSection(new ContentPage());
826-
827-
shellItem.Items.Add(shellSection1);
828-
shellItem.Items.Add(shellSection2);
829-
shellItem2.Items.Add(shellSection3);
830-
shellItem2.Items.Add(shellSection4);
831-
832-
833-
shell.Items.Add(shellItem);
834-
shell.Items.Add(shellItem2);
835-
IShellController shellController = (IShellController)shell;
836-
var groups = shellController.GenerateFlyoutGrouping();
837-
838-
Assert.AreEqual(groups.Count, 1);
839-
Assert.AreEqual(groups[0].Count, 2);
840-
}
764+
841765

842766

843767
[Test]

Xamarin.Forms.Core.UnitTests/Xamarin.Forms.Core.UnitTests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Compile Include="DeviceUnitTests.cs" />
109109
<Compile Include="EffectiveFlowDirectionExtensions.cs" />
110110
<Compile Include="ShellElementCollectionTests.cs" />
111+
<Compile Include="ShellFlyoutItemGroupTests.cs" />
111112
<Compile Include="ShellFlyoutItemTemplateTests.cs" />
112113
<Compile Include="ShellModalTests.cs" />
113114
<Compile Include="ShellNavigatingTests.cs" />
@@ -304,4 +305,4 @@
304305
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\tools\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
305306
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\build\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
306307
</Target>
307-
</Project>
308+
</Project>

Xamarin.Forms.Core/Shell/BaseShellItem.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,22 @@ static void UpdateFlyoutItemStyles(Grid flyoutItemCell, IStyleSelectable source)
308308
.StyleClass = bindableObjectStyle;
309309
}
310310

311+
BindableObject NonImplicitParent
312+
{
313+
get
314+
{
315+
if (Parent is Shell)
316+
return Parent;
317+
318+
var parent = (BaseShellItem)Parent;
319+
320+
if (!Routing.IsImplicit(parent))
321+
return parent;
322+
323+
return parent.NonImplicitParent;
324+
}
325+
}
326+
311327
internal static DataTemplate CreateDefaultFlyoutItemCell(string textBinding, string iconBinding)
312328
{
313329
return new DataTemplate(() =>
@@ -359,6 +375,16 @@ internal static DataTemplate CreateDefaultFlyoutItemCell(string textBinding, str
359375
{
360376
Property = VisualElement.BackgroundColorProperty,
361377
Value = new Color(0.95)
378+
379+
});
380+
}
381+
382+
if (Device.RuntimePlatform == Device.UWP)
383+
{
384+
normalState.Setters.Add(new Setter
385+
{
386+
Property = VisualElement.BackgroundColorProperty,
387+
Value = Color.Transparent
362388
});
363389
}
364390

@@ -458,4 +484,4 @@ public interface IQueryAttributable
458484
{
459485
void ApplyQueryAttributes(IDictionary<string, string> query);
460486
}
461-
}
487+
}

0 commit comments

Comments
 (0)