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

[Bug] Correct the transformation calculation of views #11933

Merged
merged 17 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all 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,109 @@
<controls:TestContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
x:Class="Xamarin.Forms.Controls.Issues.Issue11931"
Title="Issue 11931">

<controls:TestContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="WidthRequest" Value="100" />
<Setter Property="BackgroundColor" Value="#EE888888" />
<Setter Property="FontSize" Value="12" />
<Setter Property="HeightRequest" Value="32" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Rotation" Value="{Binding Value, Source={x:Reference rotation}}" />
</Style>
<Style TargetType="BoxView">
<Setter Property="VerticalOptions" Value="Fill" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="WidthRequest" Value="1" />
<Setter Property="Color" Value="LightGray" />
</Style>
<Style TargetType="Label">
<Setter Property="HorizontalOptions" Value="Start" />
</Style>
</ResourceDictionary>
</controls:TestContentPage.Resources>

<StackLayout>
<Label Padding="12" BackgroundColor="Black" TextColor="White"
HorizontalOptions="Fill"
Text="The buttons should completely cover the bright red boxes" />

<Slider x:Name="rotation" Minimum="-180" Maximum="180" />

<ScrollView VerticalOptions="FillAndExpand" Orientation="Both">
<Grid Margin="0" Padding="55,5,5,5">
<BoxView Margin="0,0,0,0" />
<BoxView Margin="50,0,0,0" />
<BoxView Margin="100,0,0,0" Color="Black" />
<BoxView Margin="150,0,0,0" />
<BoxView Margin="200,0,0,0" Color="Black" WidthRequest="3" />
<BoxView Margin="250,0,0,0" />
<BoxView Margin="300,0,0,0" Color="Black" />
<BoxView Margin="350,0,0,0" />

<Grid>
<Label Text="0" />
<Label Text="50" Margin="50,0,0,0" />
<Label Text="100" Margin="100,0,0,0" />
<Label Text="150" Margin="150,0,0,0" />
<Label Text="200" Margin="200,0,0,0" />
<Label Text="250" Margin="250,0,0,0" />
<Label Text="300" Margin="300,0,0,0" />
<Label Text="350" Margin="350,0,0,0" />
</Grid>

<Grid Margin="0,30,0,0">
<StackLayout Spacing="6">
<Label Text=" " />

<BoxView Color="Red" Margin="0,0,0,0" WidthRequest="100" HeightRequest="32" />
<BoxView Color="Red" Margin="-50,0,0,0" WidthRequest="200" HeightRequest="32" />
<BoxView Color="Red" Margin="0,0,0,0" WidthRequest="200" HeightRequest="32" />

<Label Text=" " />

<BoxView Color="Red" Margin="200,0,0,0" WidthRequest="100" HeightRequest="32" />
<BoxView Color="Red" Margin="150,0,0,0" WidthRequest="200" HeightRequest="32" />
<BoxView Color="Red" Margin="200,0,0,0" WidthRequest="200" HeightRequest="32" />

<Label Text=" " />

<StackLayout Spacing="16" Margin="0,8,0,0">
<BoxView Color="Red" Margin="50,0,0,0" WidthRequest="400" HeightRequest="64" />
<BoxView Color="Red" Margin="200,0,0,0" WidthRequest="400" HeightRequest="64" />
</StackLayout>
</StackLayout>

<StackLayout Spacing="6">
<Label Text="simple scale X" BackgroundColor="#AAFFFFFF" />

<Button Text="default" ScaleX="1" TranslationX="0" />
<Button Text="scale 2x" ScaleX="2" TranslationX="0" />
<Button Text="left scale 2x" ScaleX="2" TranslationX="0" AnchorX="0" />

<Label Text="Scale X then translate X to 200" BackgroundColor="#AAFFFFFF" />

<Button Text="default" ScaleX="1" TranslationX="200" />
<Button Text="scale 2x" ScaleX="2" TranslationX="200" />
<Button Text="left scale 2x" ScaleX="2" TranslationX="200" AnchorX="0" />

<Label Text="Scale 2x then scale X then translate to 200" BackgroundColor="#AAFFFFFF" />

<StackLayout Spacing="48" Margin="0,24,0,0">
<Button Text="scale 2x" Scale="2" ScaleX="2" TranslationX="200" />
<Button Text="left scale 2x" Scale="2" ScaleX="2" TranslationX="200" AnchorX="0" />
</StackLayout>
</StackLayout>
</Grid>

</Grid>
</ScrollView>
</StackLayout>

</controls:TestContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Xamarin.Forms.Internals;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Shapes;
using System.Collections.Generic;

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

namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.ViewBaseTests)]
#endif
[Preserve(AllMembers = true)]
[Issue(
IssueTracker.Github, 11931,
"[Bug] View translation is incorrectly calculated",
PlatformAffected.All)]
public partial class Issue11931: TestContentPage
{
public Issue11931()
{
#if APP
InitializeComponent();
#endif
}

protected override void Init()
{

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue11962.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10744.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10909.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11931.xaml.cs">
<DependentUpon>Issue11931.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue11709.xaml.cs">
<DependentUpon>Issue11709.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -1640,6 +1643,9 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue10672.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue11931.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue1497.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
Expand Down
41 changes: 41 additions & 0 deletions Xamarin.Forms.Platform.Android.UnitTests/TransformationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Collections;
using System.Threading.Tasks;
using NUnit.Framework;
using NUnit.Framework.Internal;

namespace Xamarin.Forms.Platform.Android.UnitTests
{
[TestFixture]
public class TransformationTests : PlatformTestFixture
{
static IEnumerable TransformationCases
{
get
{
foreach (var element in BasicElements)
{
element.TranslationX = 10.0;
element.TranslationY = 30.0;
element.Rotation = 248.0;
element.Scale = 2.0;
element.ScaleX = 2.0;
yield return CreateTestCase(element);
}
}
}

[Test, Category("Transformation"), TestCaseSource(nameof(TransformationCases))]
[Description("View transformation should match renderer transformation")]
public async Task TransformationConsistent(View element)
{
var expected = (Context.ToPixels(10d), Context.ToPixels(30d), 248d, 4d, 2d);
var actual = await GetRendererProperty(element, ver =>
{
var v = ver.View;
return (v.TranslationX, v.TranslationY, v.Rotation, v.ScaleX, v.ScaleY);
}, requiresParent: true);

Assert.That(actual, Is.EqualTo(expected));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="ButtonTests.cs" />
<Compile Include="BackgroundTests.cs" />
<Compile Include="TestActivity.cs" />
<Compile Include="TransformationTests.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,8 @@ protected virtual void ApplyTransformation()
map.PopulatePoints(geometry, 0);

bool changed = false;
ApplyRotation(map, geometry, ref changed);
ApplyScale(map, geometry, ref changed);
ApplyRotation(map, geometry, ref changed);
ApplyTranslation(map, geometry, ref changed);

NativeView.IsMapEnabled = changed;
Expand Down
50 changes: 50 additions & 0 deletions Xamarin.Forms.Platform.UAP.UnitTests/TransformationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections;
using System.Threading.Tasks;
using NUnit.Framework;
using Windows.UI.Xaml;
using WCompositeTransform = Windows.UI.Xaml.Media.CompositeTransform;

namespace Xamarin.Forms.Platform.UAP.UnitTests
{
[TestFixture]
public class TransformationTests : PlatformTestFixture
{
static IEnumerable TransformationCases
{
get
{
foreach (var element in BasicViews)
{
element.TranslationX = 10.0;
element.TranslationY = 30.0;
element.Rotation = 248.0;
element.Scale = 2.0;
element.ScaleX = 2.0;
yield return CreateTestCase(element);
}
}
}

[Test, Category("Transformation"), TestCaseSource(nameof(TransformationCases))]
[Description("View transformation should match renderer transformation")]
public async Task TransformationConsistent(View view)
Copy link
Contributor

Choose a reason for hiding this comment

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

❤️

{
var expected = (10d, 30d, 248d, 4d, 2d);
var actual = await GetRendererProperty(view, ver =>
{
var t = GetTransform(ver.ContainerElement);
return (t.TranslateX, t.TranslateY, t.Rotation, t.ScaleX, t.ScaleY);
});
Assert.That(actual, Is.EqualTo(expected));
}

WCompositeTransform GetTransform(FrameworkElement fe)
{
if (fe.RenderTransform is WCompositeTransform transform)
return transform;

throw new Exception("No rotation found");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
<Compile Include="ScaleTests.cs" />
<Compile Include="ScrollBarVisibilityTests.cs" />
<Compile Include="ShellTests.cs" />
<Compile Include="TransformationTests.cs" />
<EmbeddedResource Include="Properties\Xamarin.Forms.Platform.UAP.UnitTests.rd.xml" />
</ItemGroup>
<ItemGroup>
Expand Down
8 changes: 4 additions & 4 deletions Xamarin.Forms.Platform.UAP/VisualElementTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,8 @@ static void UpdateRotation(VisualElement view, FrameworkElement frameworkElement
{
CenterOfRotationX = anchorX,
CenterOfRotationY = anchorY,
GlobalOffsetX = scaleX == 0 ? 0 : translationX / scaleX,
GlobalOffsetY = scaleY == 0 ? 0 : translationY / scaleY,
GlobalOffsetX = translationX,
GlobalOffsetY = translationY,
RotationX = -rotationX,
RotationY = -rotationY,
RotationZ = -rotation
Expand All @@ -760,8 +760,8 @@ static void UpdateRotation(VisualElement view, FrameworkElement frameworkElement
Rotation = rotation,
ScaleX = scaleX,
ScaleY = scaleY,
TranslateX = scaleX == 0 ? 0 : translationX / scaleX,
TranslateY = scaleY == 0 ? 0 : translationY / scaleY
TranslateX = translationX,
TranslateY = translationY
};
}
}
Expand Down
21 changes: 10 additions & 11 deletions Xamarin.Forms.Platform.WPF/VisualElementTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,31 +279,30 @@ void UpdateScaleAndTranslateAndRotation()
double translationX = Element.TranslationX;
double translationY = Element.TranslationY;
double scale = Element.Scale;

double offsetX = scale == 0 ? 0 : translationX / scale;
double offsetY = scale == 0 ? 0 : translationY / scale;
double scaleX = Element.ScaleX * scale;
double scaleY = Element.ScaleY * scale;

Control.RenderTransformOrigin = new System.Windows.Point(anchorX, anchorY);
Control.RenderTransform = new WTransformGroup()
{
Children = new WTransformCollection()
{
new WScaleTransform
{
ScaleX = scaleX,
ScaleY = scaleY
},
new WRotateTransform()
{
CenterX = anchorX,
CenterY = anchorY,
Angle = Element.Rotation
Angle = rotation
},
new WTranslateTransform()
{
X = offsetX,
Y = offsetY
X = translationX,
Y = translationY
},
new WScaleTransform
{
ScaleX = scale,
ScaleY = scale
}
}
};
}
Expand Down
Loading