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

Commit

Permalink
Merge branch '3.1.0' into 3.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneDelcroix committed Jul 30, 2018
2 parents d675b3e + 72ad5ca commit 2b74434
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;


#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 3000, "Horizontal ScrollView breaks scrolling when flowdirection is set to rtl")]
#if UITEST
[NUnit.Framework.Category(UITestCategories.ScrollView)]
#endif
public class Issue3000 : TestContentPage
{
const string kSuccess = "Success";

protected override void Init()
{
ScrollView view = new ScrollView();
StackLayout parent = new StackLayout();
Label instructions = new Label() { Text = "Scroll X should not be zero Scroll Y should be zero" };
Label scrollPositions = new Label();
Label outcome = new Label();

parent.Children.Add(instructions);
parent.Children.Add(scrollPositions);
parent.Children.Add(outcome);

view.Scrolled += (_, __) =>
{
if (outcome.Text == kSuccess)
{
return;
}
scrollPositions.Text = $"ScrollX: {view.ScrollX} ScrollY: {view.ScrollY}";
if (view.ScrollY == 0 && view.ScrollX > 0)
{
outcome.Text = kSuccess;
}
else
{
outcome.Text = "Fail";
}
};

view.Orientation = ScrollOrientation.Both;

StackLayout layout = new StackLayout();
layout.Orientation = StackOrientation.Horizontal;
layout.Children.Add(new Label() { Text = "LEFT" });
for (int i = 0; i < 80; i++)
layout.Children.Add(new Image() { BackgroundColor = Color.Pink, Source = "coffee.png" });
layout.Children.Add(new Label() { Text = "RIGHT" });



StackLayout layoutDown = new StackLayout();
for (int i = 0; i < 80; i++)
layoutDown.Children.Add(new Image() { BackgroundColor = Color.Pink, Source = "coffee.png" });

view.FlowDirection = FlowDirection.RightToLeft;
parent.Children.Insert(0, new Button()
{
Text = "click me please",
Command = new Command(() =>
{
if (view.FlowDirection == FlowDirection.LeftToRight)
{
view.FlowDirection = FlowDirection.RightToLeft;
}
else
{
view.FlowDirection = FlowDirection.LeftToRight;
}
})
});

parent.Children.Insert(0, new Button()
{
Text = "reset this view",
Command = new Command(() =>
{
Application.Current.MainPage = new Issue3000();
})
});

parent.Children.Insert(0, new Label()
{
Text = "right to left text",
});

parent.Children.Insert(0, new Label()
{
Text = "left to right text"
});

view.Content = new StackLayout()
{
Children =
{
layout, layoutDown
}
};

parent.Children.Add(view);
Content = parent;
}


#if UITEST
[Test]
public void RtlScrollViewStartsScrollToRight()
{
RunningApp.WaitForElement(kSuccess);
}
#endif

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue1556.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1799.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1931.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3000.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3053.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2617.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3087.cs" />
Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Core/Cells/Cell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ EffectiveFlowDirection IFlowDirectionController.EffectiveFlowDirection
}
}

bool IFlowDirectionController.ApplyEffectiveFlowDirectionToChildContainer => true;

IFlowDirectionController FlowController => this;

public IList<MenuItem> ContextActions
Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Core/IFlowDirectionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ internal interface IFlowDirectionController
double Width { get; }

void NotifyFlowDirectionChanged();

bool ApplyEffectiveFlowDirectionToChildContainer { get; }
}
}
4 changes: 2 additions & 2 deletions Xamarin.Forms.Core/Layout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public static void LayoutChildIntoBoundingRegion(VisualElement child, Rectangle
{
var parent = child.Parent as IFlowDirectionController;
bool isRightToLeft = false;
if (parent != null && (isRightToLeft = parent.EffectiveFlowDirection.IsRightToLeft()))
if (parent != null && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
region = new Rectangle(parent.Width - region.Right, region.Y, region.Width, region.Height);

var view = child as View;
Expand Down Expand Up @@ -280,7 +280,7 @@ internal static void LayoutChildIntoBoundingRegion(View child, Rectangle region,
{
var parent = child.Parent as IFlowDirectionController;
bool isRightToLeft = false;
if (parent != null && (isRightToLeft = parent.EffectiveFlowDirection.IsRightToLeft()))
if (parent != null && (isRightToLeft = parent.ApplyEffectiveFlowDirectionToChildContainer && parent.EffectiveFlowDirection.IsRightToLeft()))
region = new Rectangle(parent.Width - region.Right, region.Y, region.Width, region.Height);

if (region.Size != childSizeRequest.Request)
Expand Down
8 changes: 4 additions & 4 deletions Xamarin.Forms.Core/ScrollView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Xamarin.Forms
{
[ContentProperty("Content")]
[RenderWith(typeof(_ScrollViewRenderer))]
public class ScrollView : Layout, IScrollViewController, IElementConfiguration<ScrollView>
public class ScrollView : Layout, IScrollViewController, IElementConfiguration<ScrollView>, IFlowDirectionController
{
public static readonly BindableProperty OrientationProperty = BindableProperty.Create("Orientation", typeof(ScrollOrientation), typeof(ScrollView), ScrollOrientation.Vertical);

Expand Down Expand Up @@ -149,9 +149,7 @@ public void SetScrolledPosition(double x, double y)
ScrollX = x;
ScrollY = y;

EventHandler<ScrolledEventArgs> handler = Scrolled;
if (handler != null)
handler(this, new ScrolledEventArgs(x, y));
Scrolled?.Invoke(this, new ScrolledEventArgs(x, y));
}

public event EventHandler<ScrolledEventArgs> Scrolled;
Expand Down Expand Up @@ -184,6 +182,8 @@ public Task ScrollToAsync(Element element, ScrollToPosition position, bool anima
return _scrollCompletionSource.Task;
}

bool IFlowDirectionController.ApplyEffectiveFlowDirectionToChildContainer => false;

protected override void LayoutChildren(double x, double y, double width, double height)
{
if (_content != null)
Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Core/VisualElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,8 @@ void OnUnfocus()
unFocus(this, new FocusEventArgs(this, false));
}

bool IFlowDirectionController.ApplyEffectiveFlowDirectionToChildContainer => true;

void IFlowDirectionController.NotifyFlowDirectionChanged()
{
SetFlowDirectionFromParent(this);
Expand Down
3 changes: 3 additions & 0 deletions Xamarin.Forms.Platform.Android/ContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public static float ToPixels(this Context self, double dp)
public static bool HasRtlSupport(this Context self) =>
(self.ApplicationInfo.Flags & AApplicationInfoFlags.SupportsRtl) == AApplicationInfoFlags.SupportsRtl;

public static int TargetSdkVersion(this Context self) =>
(int)self.ApplicationInfo.TargetSdkVersion;

internal static double GetThemeAttributeDp(this Context self, int resource)
{
using (var value = new TypedValue())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal static void UpdateFlowDirection(this AView view, IVisualElementControll
if (view == null || controller == null || (int)Build.VERSION.SdkInt < 17)
return;

// if android:targetSdkVersion < 17 setting these has no effect
if (controller.EffectiveFlowDirection.IsRightToLeft())
view.LayoutDirection = ALayoutDirection.Rtl;
else if (controller.EffectiveFlowDirection.IsLeftToRight())
Expand Down
35 changes: 34 additions & 1 deletion Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class ScrollViewRenderer : AScrollView, IVisualElementRenderer, IEffectCo
int _previousBottom;
bool _isEnabled;
bool _disposed;
LayoutDirection _prevLayoutDirection = LayoutDirection.Ltr;
bool _checkedForRtlScroll = false;

public ScrollViewRenderer(Context context) : base(context)
{
Expand Down Expand Up @@ -93,6 +95,7 @@ public void SetElement(VisualElement element)
UpdateIsEnabled();
UpdateHorizontalScrollBarVisibility();
UpdateVerticalScrollBarVisibility();
UpdateFlowDirection();

element.SendViewInitialized(this);

Expand All @@ -103,6 +106,22 @@ public void SetElement(VisualElement element)
EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
}

void UpdateFlowDirection()
{
if (Element is IVisualElementController controller)
{
var flowDirection = controller.EffectiveFlowDirection.IsLeftToRight()
? LayoutDirection.Ltr
: LayoutDirection.Rtl;

if (_prevLayoutDirection != flowDirection && _hScrollView != null)
{
_prevLayoutDirection = flowDirection;
_hScrollView.LayoutDirection = flowDirection;
}
}
}

public VisualElementTracker Tracker { get; private set; }

public void UpdateLayout()
Expand Down Expand Up @@ -229,12 +248,19 @@ protected override void OnLayout(bool changed, int left, int top, int right, int
base.OnLayout(changed, left, top, right, bottom);
if (_view.Content != null && _hScrollView != null)
_hScrollView.Layout(0, 0, right - left, Math.Max(bottom - top, (int)Context.ToPixels(_view.Content.Height)));
else if(_view.Content != null && requestContainerLayout)
else if (_view.Content != null && requestContainerLayout)
_container?.RequestLayout();

// if the target sdk >= 17 then setting the LayoutDirection on the scroll view natively takes care of the scroll
if (Context.TargetSdkVersion() < 17 && !_checkedForRtlScroll && _hScrollView != null && Element is IVisualElementController controller && controller.EffectiveFlowDirection.IsRightToLeft())
_hScrollView.ScrollX = _container.MeasuredWidth - _hScrollView.MeasuredWidth - _hScrollView.ScrollX;

_checkedForRtlScroll = true;
}

protected override void OnScrollChanged(int l, int t, int oldl, int oldt)
{
_checkedForRtlScroll = true;
base.OnScrollChanged(l, t, oldl, oldt);
var context = Context;
UpdateScrollPosition(context.FromPixels(l), context.FromPixels(t));
Expand Down Expand Up @@ -293,6 +319,8 @@ void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateHorizontalScrollBarVisibility();
else if (e.PropertyName == ScrollView.VerticalScrollBarVisibilityProperty.PropertyName)
UpdateVerticalScrollBarVisibility();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
}

void UpdateIsEnabled()
Expand All @@ -312,6 +340,8 @@ void LoadContent()

async void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e)
{
_checkedForRtlScroll = true;

if (!_isAttached)
{
return;
Expand Down Expand Up @@ -417,7 +447,10 @@ void UpdateOrientation()
if (_view.Orientation == ScrollOrientation.Horizontal || _view.Orientation == ScrollOrientation.Both)
{
if (_hScrollView == null)
{
_hScrollView = new AHorizontalScrollView(Context, this);
UpdateFlowDirection();
}

((AHorizontalScrollView)_hScrollView).IsBidirectional = _isBidirectional = _view.Orientation == ScrollOrientation.Both;

Expand Down
Loading

0 comments on commit 2b74434

Please sign in to comment.