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

Remove GetEffectiveFlowDirection and defer flow direction handling to platforms #9558

Merged
merged 9 commits into from
Aug 27, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,7 @@ void UpdateSearchBarHorizontalTextAlignment(UITextField textField, IView view =
if (textField == null)
return;

textField.TextAlignment = _searchHandler.HorizontalTextAlignment.ToPlatformHorizontal();
if (view != null)
{
textField.TextAlignment = textField.TextAlignment.AdjustForFlowDirection(view);
}
textField.TextAlignment = _searchHandler.HorizontalTextAlignment.ToPlatformHorizontal(textField.EffectiveUserInterfaceLayoutDirection);
}

void UpdateSearchBarVerticalTextAlignment(UITextField textField)
Expand Down
22 changes: 0 additions & 22 deletions src/Core/src/Core/Extensions/IViewExtensions.cs

This file was deleted.

10 changes: 9 additions & 1 deletion src/Core/src/Handlers/ContentView/ContentViewHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ static void UpdateContent(IContentViewHandler handler)
handler.PlatformView.ClearSubviews();

if (handler.VirtualView.PresentedContent is IView view)
handler.PlatformView.AddSubview(view.ToPlatform(handler.MauiContext));
{
var platformView = view.ToPlatform(handler.MauiContext);
handler.PlatformView.AddSubview(platformView);

if (view.FlowDirection == FlowDirection.MatchParent)
{
platformView.UpdateFlowDirection(view);
}
}
}

public static void MapContent(IContentViewHandler handler, IContentView page)
Expand Down
4 changes: 2 additions & 2 deletions src/Core/src/Handlers/Entry/EntryHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void OnFocusedChange(object? sender, FocusChangeEventArgs e)
void OnTouch(object? sender, TouchEventArgs e) =>
e.Handled =
_clearButtonVisible && VirtualView != null &&
PlatformView.HandleClearButtonTouched(VirtualView.GetEffectiveFlowDirection(), e, GetClearButtonDrawable);
PlatformView.HandleClearButtonTouched(e, GetClearButtonDrawable);

void OnEditorAction(object? sender, EditorActionEventArgs e)
{
Expand Down Expand Up @@ -188,7 +188,7 @@ internal void ShowClearButton()

var drawable = GetClearButtonDrawable();

if (VirtualView.GetEffectiveFlowDirection() == FlowDirection.RightToLeft)
if (PlatformView.LayoutDirection == LayoutDirection.Rtl)
{
PlatformView.SetCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
}
Expand Down
3 changes: 0 additions & 3 deletions src/Core/src/Handlers/Entry/EntryHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ public partial class EntryHandler : IEntryHandler

static EntryHandler()
Copy link
Member

@PureWeen PureWeen Aug 25, 2022

Choose a reason for hiding this comment

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

Can we just delete the entire static ctor now?

Same question for LabelHandler/LayoutHandler/PickerHandler/SearchBarHandler

{
#if __IOS__
Mapper.PrependToMapping(nameof(IView.FlowDirection), (h, __) => h.UpdateValue(nameof(ITextAlignment.HorizontalTextAlignment)));
#endif
}

public EntryHandler() : base(Mapper)
Expand Down
3 changes: 0 additions & 3 deletions src/Core/src/Handlers/Label/LabelHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ public partial class LabelHandler : ILabelHandler

static LabelHandler()
{
#if __IOS__
Mapper.PrependToMapping(nameof(IView.FlowDirection), (h, __) => h.UpdateValue(nameof(ITextAlignment.HorizontalTextAlignment)));
#endif
}

public LabelHandler() : base(Mapper)
Expand Down
16 changes: 14 additions & 2 deletions src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ public void Add(IView child)
_ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class.");

var targetIndex = VirtualView.GetLayoutHandlerIndex(child);
PlatformView.InsertSubview(child.ToPlatform(MauiContext), targetIndex);
var childPlatformView = child.ToPlatform(MauiContext);
PlatformView.InsertSubview(childPlatformView, targetIndex);

if (child.FlowDirection == FlowDirection.MatchParent)
{
childPlatformView.UpdateFlowDirection(child);
}
}

public void Remove(IView child)
Expand All @@ -77,7 +83,13 @@ public void Insert(int index, IView child)
_ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class.");

var targetIndex = VirtualView.GetLayoutHandlerIndex(child);
PlatformView.InsertSubview(child.ToPlatform(MauiContext), targetIndex);
var childPlatformView = child.ToPlatform(MauiContext);
PlatformView.InsertSubview(childPlatformView, targetIndex);

if (child.FlowDirection == FlowDirection.MatchParent)
{
childPlatformView.UpdateFlowDirection(child);
}
}

public void Update(int index, IView child)
Expand Down
3 changes: 0 additions & 3 deletions src/Core/src/Handlers/Picker/PickerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public partial class PickerHandler : IPickerHandler

static PickerHandler()
{
#if __IOS__
Mapper.PrependToMapping(nameof(IView.FlowDirection), (h, __) => h.UpdateValue(nameof(ITextAlignment.HorizontalTextAlignment)));
#endif
}

public PickerHandler() : base(Mapper, CommandMapper)
Expand Down
3 changes: 0 additions & 3 deletions src/Core/src/Handlers/SearchBar/SearchBarHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ public partial class SearchBarHandler : ISearchBarHandler

static SearchBarHandler()
{
#if __IOS__
Mapper.PrependToMapping(nameof(IView.FlowDirection), (h, __) => h.UpdateValue(nameof(ITextAlignment.HorizontalTextAlignment)));
#endif
}

public SearchBarHandler() : base(Mapper)
Expand Down
9 changes: 9 additions & 0 deletions src/Core/src/Handlers/ViewHandlerExtensions.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ internal static void PlatformArrangeHandler(this IViewHandler viewHandler, Rect
var bottom = Context.ToPixels(frame.Bottom);
var right = Context.ToPixels(frame.Right);

var viewParent = platformView.Parent;
if (viewParent?.LayoutDirection == LayoutDirection.Rtl && viewParent is View parentView)
{
// Determine the flipped left/right edges for the RTL layout
var width = right - left;
left = parentView.Width - left - width;
right = left + width;
}

platformView.Layout((int)left, (int)top, (int)right, (int)bottom);

viewHandler.Invoke(nameof(IView.Frame), frame);
Expand Down
17 changes: 14 additions & 3 deletions src/Core/src/Handlers/ViewHandlerExtensions.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,24 @@ internal static void PlatformArrangeHandler(this IViewHandler viewHandler, Rect
if (platformView == null)
return;

var centerX = rect.Center.X;
var boundsX = (double)platformView.Bounds.X;

var parent = platformView.Superview;
if (parent?.EffectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.RightToLeft)
{
// We'll need to adjust the center point to reflect the RTL layout
centerX = parent.Bounds.Right - rect.Center.X;
boundsX = boundsX - (rect.Center.X - centerX);
}

// We set Center and Bounds rather than Frame because Frame is undefined if the CALayer's transform is
// anything other than the identity (https://developer.apple.com/documentation/uikit/uiview/1622459-transform)
platformView.Center = new CoreGraphics.CGPoint(rect.Center.X, rect.Center.Y);
platformView.Center = new CGPoint(centerX, rect.Center.Y);

// The position of Bounds is usually (0,0), but in some cases (e.g., UIScrollView) it's the content offset.
// So just leave it a whatever value iOS thinks it should be.
platformView.Bounds = new CoreGraphics.CGRect(platformView.Bounds.X, platformView.Bounds.Y, rect.Width, rect.Height);
// So just leave it whatever value iOS thinks it should be (adjusted for RTL if appropriate)
platformView.Bounds = new CGRect(boundsX, platformView.Bounds.Y, rect.Width, rect.Height);

viewHandler.Invoke(nameof(IView.Frame), rect);
}
Expand Down
10 changes: 1 addition & 9 deletions src/Core/src/Layouts/AbsoluteLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,9 @@ public override Size ArrangeChildren(Rect bounds)

double top = padding.Top + bounds.Top;
double left = padding.Left + bounds.Left;
double right = bounds.Right - padding.Right;
double availableWidth = bounds.Width - padding.HorizontalThickness;
double availableHeight = bounds.Height - padding.VerticalThickness;

bool leftToRight = AbsoluteLayout.ShouldArrangeLeftToRight();

for (int n = 0; n < AbsoluteLayout.Count; n++)
{
var child = AbsoluteLayout[n];
Expand Down Expand Up @@ -96,12 +93,7 @@ public override Size ArrangeChildren(Rect bounds)
destination.Y = (availableHeight - destination.Height) * destination.Y;
}

// Figure out where we're starting from (the left edge of the padded area, or the right edge)
if (leftToRight)
destination.X += left;
else
destination.X = right - destination.X - destination.Width;

destination.X += left;
destination.Y += top;

child.Arrange(destination);
Expand Down
9 changes: 0 additions & 9 deletions src/Core/src/Layouts/GridLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ public override Size ArrangeChildren(Rect bounds)

_gridStructure.AdjustStarsForArrange(bounds.Size);

var reverseColumns = Grid.ColumnDefinitions.Count > 1 && !Grid.ShouldArrangeLeftToRight();

foreach (var view in Grid)
{
if (view.Visibility == Visibility.Collapsed)
Expand All @@ -46,13 +44,6 @@ public override Size ArrangeChildren(Rect bounds)
}

var cell = _gridStructure.GetCellBoundsFor(view, bounds.Left, bounds.Top);

if (reverseColumns)
{
var adjustedXPosition = bounds.Right - cell.Left - cell.Width;
cell.Left = adjustedXPosition;
}

view.Arrange(cell);
}

Expand Down
38 changes: 10 additions & 28 deletions src/Core/src/Layouts/HorizontalStackLayoutManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Graphics;

namespace Microsoft.Maui.Layouts
Expand Down Expand Up @@ -46,18 +45,15 @@ public override Size Measure(double widthConstraint, double heightConstraint)
public override Size ArrangeChildren(Rect bounds)
{
var padding = Stack.Padding;
double spacing = Stack.Spacing;
var childCount = Stack.Count;

double top = padding.Top + bounds.Top;

var height = bounds.Height - padding.VerticalThickness;
double stackWidth;

bool leftToRight = Stack.ShouldArrangeLeftToRight();

// Figure out where we're starting from (the left edge of the padded area, or the right edge)
double xPosition = leftToRight ? padding.Left + bounds.Left : bounds.Right - padding.Right;

// If we're arranging from the right, spacing will be added to the left
double spacingDelta = leftToRight ? Stack.Spacing : -Stack.Spacing;
// Figure out where we're starting from
double xPosition = padding.Left + bounds.Left;

for (int n = 0; n < Stack.Count; n++)
{
Expand All @@ -68,39 +64,25 @@ public override Size ArrangeChildren(Rect bounds)
continue;
}

xPosition += leftToRight
? ArrangeChildFromLeftEdge(child, height, top, xPosition)
: ArrangeChildFromRightEdge(child, height, top, xPosition);
xPosition += ArrangeChild(child, height, top, xPosition);

if (n < Stack.Count - 1)
if (n < childCount - 1)
{
// If we have more than one child and we're not on the last one, add spacing
xPosition += spacingDelta;
xPosition += spacing;
}
}

// If we started from the left, the total width is the current x position;
// If we started from the right, it's the difference between the right edge and the current x position
stackWidth = leftToRight ? xPosition : bounds.Right - xPosition;

var actual = new Size(stackWidth, height);
var actual = new Size(xPosition, height);

return actual.AdjustForFill(bounds, Stack);
}

static double ArrangeChildFromLeftEdge(IView child, double height, double top, double x)
static double ArrangeChild(IView child, double height, double top, double x)
{
var destination = new Rect(x, top, child.DesiredSize.Width, height);
child.Arrange(destination);
return destination.Width;
}

static double ArrangeChildFromRightEdge(IView child, double height, double top, double x)
{
var width = child.DesiredSize.Width;
var destination = new Rect(x - width, top, width, height);
child.Arrange(destination);
return -destination.Width;
}
}
}
35 changes: 2 additions & 33 deletions src/Core/src/Layouts/LayoutExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Primitives;
using static Microsoft.Maui.Primitives.Dimension;
Expand Down Expand Up @@ -78,27 +79,8 @@ static double AlignHorizontal(IView view, Rect bounds, Thickness margin)
}

var desiredWidth = view.DesiredSize.Width;
var startX = bounds.X;

if (view.ShouldArrangeLeftToRight())
{
return AlignHorizontal(startX, margin.Left, margin.Right, bounds.Width, desiredWidth, alignment);
}

// If the flowdirection is RTL, then we can use the same logic to determine the X position of the Frame;
// we just have to flip a few parameters. First we flip the alignment if it's start or end:

if (alignment == LayoutAlignment.End)
{
alignment = LayoutAlignment.Start;
}
else if (alignment == LayoutAlignment.Start)
{
alignment = LayoutAlignment.End;
}

// And then we swap the left and right margins:
return AlignHorizontal(startX, margin.Right, margin.Left, bounds.Width, desiredWidth, alignment);
return AlignHorizontal(bounds.X, margin.Left, margin.Right, bounds.Width, desiredWidth, alignment);
}

static double AlignHorizontal(double startX, double startMargin, double endMargin, double boundsWidth,
Expand Down Expand Up @@ -206,18 +188,5 @@ public static Size AdjustForFill(this Size size, Rect bounds, IView view)

return size;
}

public static bool ShouldArrangeLeftToRight(this IView view)
{
var viewFlowDirection = view.GetEffectiveFlowDirection();

// The various platforms handle layout and flow direction in different ways; some platforms
// helpfully flip the coordinates of arrange calls when in RTL mode, others don't
// So this gives us a place to ask the platform (via LayoutHandler) whether we need to do
// the layout work to flip RTL stuff in our cross-platform layouts or not.
var layoutFlowDirection = LayoutHandler.GetLayoutFlowDirection(viewFlowDirection);

return layoutFlowDirection == FlowDirection.LeftToRight;
}
}
}
8 changes: 5 additions & 3 deletions src/Core/src/Platform/Android/EditTextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ internal static bool IsCompletedAction(this EditorActionEventArgs e)
/// This will return True to handle OnTouch to prevent re-activating keyboard after clearing the text.
/// </summary>
/// <returns>True if clear button is clicked and Text is cleared. False if not.</returns>
internal static bool HandleClearButtonTouched(this EditText? platformView, FlowDirection flowDirection, TouchEventArgs? touchEvent, Func<Drawable?>? getClearButtonDrawable)
internal static bool HandleClearButtonTouched(this EditText? platformView, TouchEventArgs? touchEvent, Func<Drawable?>? getClearButtonDrawable)
{
if (platformView is null)
return false;
Expand All @@ -368,12 +368,14 @@ internal static bool HandleClearButtonTouched(this EditText? platformView, FlowD
var x = motionEvent.RawX;
var y = motionEvent.GetY();

if ((flowDirection != FlowDirection.LeftToRight
var flowDirection = platformView.LayoutDirection;

if ((flowDirection != LayoutDirection.Ltr
|| x < platformView.Right - buttonWidth
|| x > platformView.Right - platformView.PaddingRight
|| y < platformView.PaddingTop
|| y > platformView.Height - platformView.PaddingBottom) &&
(flowDirection != FlowDirection.RightToLeft
(flowDirection != LayoutDirection.Rtl
|| x < platformView.Left + platformView.PaddingLeft
|| x > platformView.Left + buttonWidth
|| y < platformView.PaddingTop
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Platform/iOS/LabelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static void UpdateFont(this UILabel platformLabel, ITextStyle textStyle,

public static void UpdateHorizontalTextAlignment(this UILabel platformLabel, ILabel label)
{
platformLabel.TextAlignment = label.HorizontalTextAlignment.ToPlatformHorizontal(label);
platformLabel.TextAlignment = label.HorizontalTextAlignment.ToPlatformHorizontal(platformLabel.EffectiveUserInterfaceLayoutDirection);
}

// Don't use this method, it doesn't work. But we can't remove it.
Expand Down
Loading