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

Commit 298e62a

Browse files
authored
Fix Flyout Footer measuring and Content Margin (#13157)
* Fix Flyout Footer measuring and Content Margin * - fix uwp tests and cleanup android code
1 parent f783f85 commit 298e62a

File tree

4 files changed

+82
-52
lines changed

4 files changed

+82
-52
lines changed

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/HeaderFooterShellFlyout.cs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,15 @@ protected override void Init()
5252
{
5353
if (FlyoutHeaderTemplate == null)
5454
{
55-
FlyoutHeaderTemplate = new DataTemplate(() => new Label() { Text = "Header Template" });
56-
FlyoutFooterTemplate = new DataTemplate(() => new Label() { Text = "Footer Template" });
55+
FlyoutHeaderTemplate = new DataTemplate(() =>
56+
{
57+
return new Label() { Text = "Header Template" };
58+
});
59+
60+
FlyoutFooterTemplate = new DataTemplate(() =>
61+
{
62+
return new Label() { Text = "Footer Template" };
63+
});
5764
}
5865
else if (FlyoutHeaderTemplate != null)
5966
{
@@ -76,8 +83,22 @@ protected override void Init()
7683
}
7784
else
7885
{
79-
FlyoutHeader = new Label() { Text = "Header View" };
80-
FlyoutFooter = new Label() { Text = "Footer View" };
86+
FlyoutHeader = new StackLayout()
87+
{
88+
Children = {
89+
new Label() { Text = "Header" }
90+
},
91+
AutomationId = "Header View"
92+
};
93+
94+
FlyoutFooter = new StackLayout()
95+
{
96+
Orientation = StackOrientation.Horizontal,
97+
Children = {
98+
new Label() { Text = "Footer" }
99+
},
100+
AutomationId = "Footer View"
101+
};
81102
}
82103
}),
83104
AutomationId = "ToggleHeaderFooter"
@@ -138,43 +159,42 @@ protected override void Init()
138159
public void FlyoutTests()
139160
{
140161
RunningApp.WaitForElement("PageLoaded");
141-
ShowFlyout();
142162

143163
// Verify Header an Footer show up at all
144-
OpenFlyout("ToggleHeaderFooter");
164+
TapInFlyout("ToggleHeaderFooter", makeSureFlyoutStaysOpen: true);
145165
RunningApp.WaitForElement("Header View");
146166
RunningApp.WaitForElement("Footer View");
147167

148168
// Verify Template takes priority over header footer
149-
OpenFlyout("ToggleHeaderFooterTemplate");
169+
TapInFlyout("ToggleHeaderFooterTemplate", makeSureFlyoutStaysOpen: true);
150170
RunningApp.WaitForElement("Header Template");
151171
RunningApp.WaitForElement("Footer Template");
152172
RunningApp.WaitForNoElement("Header View");
153173
RunningApp.WaitForNoElement("Footer View");
154174

155175
// Verify turning off Template shows Views again
156-
OpenFlyout("ToggleHeaderFooterTemplate");
176+
TapInFlyout("ToggleHeaderFooterTemplate", makeSureFlyoutStaysOpen: true);
157177
RunningApp.WaitForElement("Header View");
158178
RunningApp.WaitForElement("Footer View");
159179
RunningApp.WaitForNoElement("Header Template");
160180
RunningApp.WaitForNoElement("Footer Template");
161181

162182
// Verify turning off header/footer clear out views correctly
163-
OpenFlyout("ToggleHeaderFooter");
183+
TapInFlyout("ToggleHeaderFooter", makeSureFlyoutStaysOpen: true);
164184
RunningApp.WaitForNoElement("Header Template");
165185
RunningApp.WaitForNoElement("Footer Template");
166186
RunningApp.WaitForNoElement("Header View");
167187
RunningApp.WaitForNoElement("Footer View");
168188

169189
// verify header and footer react to size changes
170-
OpenFlyout("ResizeHeaderFooter");
190+
TapInFlyout("ResizeHeaderFooter", makeSureFlyoutStaysOpen: true);
171191
var headerSizeSmall = RunningApp.WaitForElement("Header View")[0].Rect;
172192
var footerSizeSmall = RunningApp.WaitForElement("Footer View")[0].Rect;
173-
OpenFlyout("ResizeHeaderFooter");
193+
TapInFlyout("ResizeHeaderFooter", makeSureFlyoutStaysOpen: true);
174194
var headerSizeLarge = RunningApp.WaitForElement("Header View")[0].Rect;
175195
var footerSizeLarge = RunningApp.WaitForElement("Footer View")[0].Rect;
176196

177-
OpenFlyout("ResizeHeaderFooter");
197+
TapInFlyout("ResizeHeaderFooter", makeSureFlyoutStaysOpen: true);
178198
var headerSizeSmall2 = RunningApp.WaitForElement("Header View")[0].Rect;
179199
var footerSizeSmall2 = RunningApp.WaitForElement("Footer View")[0].Rect;
180200

@@ -183,19 +203,6 @@ public void FlyoutTests()
183203
Assert.AreEqual(headerSizeSmall2.Height, headerSizeSmall.Height);
184204
Assert.AreEqual(footerSizeSmall2.Height, footerSizeSmall.Height);
185205
}
186-
187-
void OpenFlyout(string text)
188-
{
189-
RunningApp.Tap(text);
190-
191-
#if __WINDOWS__
192-
// UWP closes the flyout after selecting an item
193-
System.Threading.Thread.Sleep(1000);
194-
ShowFlyout();
195-
#endif
196-
}
197-
198-
199206
#endif
200207
}
201208
}

Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutTemplatedContentRenderer.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public class ShellFlyoutTemplatedContentRenderer : Java.Lang.Object, IShellFlyou
3838
int _actionBarHeight;
3939
ScrollLayoutManager _layoutManager;
4040

41+
protected IShellContext ShellContext => _shellContext;
42+
protected AView FooterView => _footerView?.NativeView;
43+
protected AView View => _rootView;
44+
4145
public ShellFlyoutTemplatedContentRenderer(IShellContext shellContext)
4246
{
4347
_shellContext = shellContext;
@@ -152,7 +156,7 @@ protected virtual void OnShellPropertyChanged(object sender, PropertyChangedEven
152156
UpdateFlyoutFooter();
153157
}
154158

155-
void UpdateFlyoutHeader()
159+
protected virtual void UpdateFlyoutHeader()
156160
{
157161
if (_headerView != null)
158162
{
@@ -184,7 +188,7 @@ void UpdateFlyoutHeader()
184188
UpdateFlyoutHeaderBehavior();
185189
}
186190

187-
void UpdateFlyoutFooter()
191+
protected virtual void UpdateFlyoutFooter()
188192
{
189193
if (_footerView != null)
190194
{
@@ -201,14 +205,17 @@ void UpdateFlyoutFooter()
201205

202206
_footerView = new ShellViewRenderer(_shellContext.AndroidContext, footer);
203207

204-
205208
_footerView.NativeView.LayoutParameters = new CoordinatorLayout.LayoutParams(LP.MatchParent, LP.WrapContent)
206209
{
207210
Gravity = (int)(GravityFlags.Bottom | GravityFlags.End)
208211
};
209212

210-
_footerView.LayoutView(_shellContext.AndroidContext.FromPixels(_rootView.LayoutParameters.Width), -1);
213+
_footerView.LayoutView(_shellContext.AndroidContext.FromPixels(_rootView.LayoutParameters.Width), double.PositiveInfinity);
211214
_rootView.AddView(_footerView.NativeView);
215+
if(_recycler?.LayoutParameters is CoordinatorLayout.LayoutParams cl)
216+
{
217+
cl.BottomMargin = (int)_shellContext.AndroidContext.ToPixels(_footerView.View.Height);
218+
}
212219
}
213220

214221
void UpdateVerticalScrollMode()

Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ void SetupMenu()
407407
SetupMenu(menu, _bottomView.MaxItemCount, ShellItem);
408408
}
409409

410-
void UpdateTabBarVisibility()
410+
protected virtual void UpdateTabBarVisibility()
411411
{
412412
if (DisplayedPage == null)
413413
return;

Xamarin.Forms.Platform.Android/Renderers/ShellViewRenderer.cs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ namespace Xamarin.Forms.Platform.Android
1212
// This is used to monitor an xplat View and apply layout changes
1313
internal class ShellViewRenderer
1414
{
15-
IVisualElementRenderer _renderer;
15+
public IVisualElementRenderer Renderer { get; private set; }
1616
View _view;
1717
WeakReference<Context> _context;
18-
private double _width;
19-
private double _height;
18+
public double Width { get; private set; }
19+
public double Height { get; private set; }
2020

2121
public ShellViewRenderer(Context context, View view)
2222
{
@@ -36,37 +36,49 @@ public View View
3636
public void TearDown()
3737
{
3838
View = null;
39-
_renderer?.Dispose();
40-
_renderer = null;
39+
Renderer?.Dispose();
40+
Renderer = null;
4141
_view = null;
4242
_context = null;
4343
}
4444

45-
public void LayoutView(double width, double height)
45+
public void LayoutView(double width, double height, double? maxWidth = null, double? maxHeight = null)
4646
{
47-
_width = width;
48-
_height = height;
47+
if (width == -1)
48+
width = double.PositiveInfinity;
49+
50+
if (height == -1)
51+
height = double.PositiveInfinity;
52+
53+
Width = width;
54+
Height = height;
4955
Context context;
5056

51-
if (_renderer == null || !(_context.TryGetTarget(out context)) || !_renderer.View.IsAlive())
57+
if (Renderer == null || !(_context.TryGetTarget(out context)) || !Renderer.View.IsAlive())
5258
return;
5359

5460
if (View == null)
5561
{
5662
var empty = MeasureSpecFactory.GetSize(0);
57-
_renderer.View.Measure(empty, empty);
63+
Renderer.View.Measure(empty, empty);
5864
return;
5965
}
6066

6167
var request = View.Measure(width, height, MeasureFlags.None);
6268

6369
var layoutParams = NativeView.LayoutParameters;
64-
if (height == -1)
70+
if (double.IsInfinity(height))
6571
height = request.Request.Height;
6672

67-
if (width == -1)
73+
if (double.IsInfinity(width))
6874
width = request.Request.Width;
6975

76+
if (height > maxHeight)
77+
height = maxHeight.Value;
78+
79+
if (width > maxWidth)
80+
width = maxWidth.Value;
81+
7082
if (layoutParams.Width != LP.MatchParent)
7183
layoutParams.Width = (int)context.ToPixels(width);
7284

@@ -75,22 +87,22 @@ public void LayoutView(double width, double height)
7587

7688
NativeView.LayoutParameters = layoutParams;
7789
View.Layout(new Rectangle(0, 0, width, height));
78-
_renderer.UpdateLayout();
90+
Renderer.UpdateLayout();
7991
}
8092

81-
public void OnViewSet(View view)
93+
public virtual void OnViewSet(View view)
8294
{
8395
if (View != null)
8496
View.SizeChanged -= OnViewSizeChanged;
8597

8698
if (View is VisualElement oldView)
8799
oldView.MeasureInvalidated -= OnViewSizeChanged;
88100

89-
if (_renderer != null)
101+
if (Renderer != null)
90102
{
91-
_renderer.View.RemoveFromParent();
92-
_renderer.Dispose();
93-
_renderer = null;
103+
Renderer.View.RemoveFromParent();
104+
Renderer.Dispose();
105+
Renderer = null;
94106
}
95107

96108
_view = view;
@@ -101,19 +113,23 @@ public void OnViewSet(View view)
101113
if (!(_context.TryGetTarget(out context)))
102114
return;
103115

104-
_renderer = Platform.CreateRenderer(view, context);
105-
Platform.SetRenderer(view, _renderer);
106-
NativeView = _renderer.View;
116+
Renderer = Platform.CreateRenderer(view, context);
117+
Platform.SetRenderer(view, Renderer);
118+
NativeView = Renderer.View;
107119

108120
if (View is VisualElement ve)
109121
ve.MeasureInvalidated += OnViewSizeChanged;
110122
else
111123
View.SizeChanged += OnViewSizeChanged;
112124
}
125+
else
126+
{
127+
NativeView = null;
128+
}
113129
}
114130

115131
void OnViewSizeChanged(object sender, EventArgs e) =>
116-
LayoutView(_width, _height);
132+
LayoutView(Width, Height);
117133

118134
public AView NativeView
119135
{

0 commit comments

Comments
 (0)