Skip to content

Commit

Permalink
[Android] fixes redraw element when changing renderer (xamarin#5233)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavel Yakovlev authored and Alexey Maltsev committed Jun 15, 2019
1 parent 8e6ec05 commit df113d9
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve (AllMembers=true)]
[Issue (IssueTracker.Github, 1332, "Frame inside frame does not resize after visibility changed", PlatformAffected.Android)]
public class Issue1332: TestContentPage
{
protected override void Init()
{
double layoutWidth = 0.6;
double layoutHeight = 150;

var red = new Frame
{
BackgroundColor = Color.Red,
Content = new Frame
{
BorderColor = Color.Black,
HeightRequest = layoutHeight,
BackgroundColor = Color.Transparent
}
};
AbsoluteLayout.SetLayoutBounds(red, new Rectangle(0, 0, layoutWidth, layoutHeight));
AbsoluteLayout.SetLayoutFlags(red, AbsoluteLayoutFlags.XProportional | AbsoluteLayoutFlags.WidthProportional);

var stack = new StackLayout
{
Children =
{
new Button
{
Text = "visibility",
Padding = 10,
Command = new Command(() => red.IsVisible = !red.IsVisible)
},
new Button
{
Text = "width",
Padding = 10,
Command = new Command(() => {
layoutWidth = layoutWidth == 0.3 ? 0.6 : 0.3;
red.IsVisible = false;
AbsoluteLayout.SetLayoutBounds(red, new Rectangle(0, 0, layoutWidth, 150));
red.IsVisible = true;
})
}
}
};
AbsoluteLayout.SetLayoutBounds(stack, new Rectangle(1, 0, layoutWidth / 2, 1));
AbsoluteLayout.SetLayoutFlags(stack, AbsoluteLayoutFlags.All);

var desc = new Label
{
Text = "Click on Visibility, then click on Width button few times." +
"The layout of the second frame must be updated to match the first."
};
AbsoluteLayout.SetLayoutBounds(desc, new Rectangle(0, 0.5, 1, 0.5));
AbsoluteLayout.SetLayoutFlags(desc, AbsoluteLayoutFlags.All);

Content = new AbsoluteLayout
{
Children =
{
red,
stack,
desc
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,33 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

#if UITEST
using NUnit.Framework;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 1760, "Content set after an await is not visible", PlatformAffected.Android)]
public class Issue1760 : TestMasterDetailPage
{
const string Before = "Before";
const string After = "After";
public const string Before = "Before";
public const string After = "After";
const int Wait = 3;

protected override void Init()
{
Master = new _1760Master();
Detail = new _1760TestPage();
Master = new _1760Master(true);
Detail = new _1760TestPage(true);
IsPresented = true;
}

[Preserve(AllMembers = true)]
public class _1760Master : ContentPage
{
public _1760Master()
readonly bool _scrollEnabled;

public _1760Master(bool scrollEnabled)
{
var instructions = new Label { Text = $"Select one of the menu items. The detail page text should change to {Before}. After {Wait} seconds the text should change to {After}." };

Expand All @@ -36,19 +42,23 @@ public _1760Master()

Content = new StackLayout{Children = { instructions, menuView }};
Title = "GH 1760 Test App";

_scrollEnabled = scrollEnabled;
}

void OnMenuClicked(object sender, SelectedItemChangedEventArgs e)
{
var mainPage = (MasterDetailPage)Parent;
mainPage.Detail = new _1760TestPage();
mainPage.Detail = new _1760TestPage(_scrollEnabled);
mainPage.IsPresented = false;
}
}

[Preserve(AllMembers = true)]
public class _1760TestPage : ContentPage
{
readonly bool _scrollEnabled;

public async Task DisplayPage()
{
IsBusy = true;
Expand All @@ -66,8 +76,9 @@ public View HeaderPageContent
set => _headerPageContent.Content = value;
}

public _1760TestPage()
public _1760TestPage(bool scrollEnabled)
{
_scrollEnabled = scrollEnabled;
CreateHeaderPage();
DisplayPage();
}
Expand All @@ -84,11 +95,57 @@ void CreateHeaderPage()

Title = "_1760 Test Page";

Content = new ScrollView
if (_scrollEnabled)
{
Content = _headerPageContent
};
Content = new ScrollView
{
Content = _headerPageContent
};
}
else
{
var _headerLabel = new Label
{
Text = Title,
TextColor = Color.FromHex("333333"),
HeightRequest = 25,
};

var headerLayout = new RelativeLayout
{
BackgroundColor = Color.White,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.Start,
};

headerLayout.Children.Add(_headerLabel,
Forms.Constraint.Constant(0),
Forms.Constraint.Constant(0),
Forms.Constraint.RelativeToParent(parent => parent.Width));

Content = new StackLayout
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Children = {
_headerLabel, _headerPageContent
}
};
}
}
}

#if UITEST && __ANDROID__
[Test]
public void Issue1760Test()
{
RunningApp.WaitForElement(Before);
RunningApp.WaitForElement(After);

RunningApp.Tap("Test Page 1");
RunningApp.WaitForElement(Before);
RunningApp.WaitForElement(After);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

#if UITEST
using NUnit.Framework;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 1760, "Content set after an await is not visible", PlatformAffected.Android, issueTestNumber: 1)]
public class Issue1760_1 : TestMasterDetailPage
{
protected override void Init()
{
Master = new Issue1760._1760Master(false);
Detail = new Issue1760._1760TestPage(false);
IsPresented = true;
}

#if UITEST && __ANDROID__
[Test]
public void Issue1760_1Test()
{
RunningApp.WaitForElement(Issue1760.Before);
RunningApp.WaitForElement(Issue1760.After);

RunningApp.Tap("Test Page 1");
RunningApp.WaitForElement(Issue1760.Before);
RunningApp.WaitForElement(Issue1760.After);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Collections.Generic;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
public class ListViewEntry
{
public int Number { get; set; }
}

[Preserve(AllMembers = true)]
public class ListViewGroup : List<ListViewEntry>
{
public string Heading { get; set; }
}

[Preserve(AllMembers = true)]
public class MainPageViewModel
{
List<ListViewGroup> _groups = new List<ListViewGroup>();

public MainPageViewModel()
{
for (int i = 0; i < 20; ++i)
{
var group = new ListViewGroup
{
Heading = $"Group {i * 5} - {(i + 1) * 5 - 1}"
};

for (int j = 0; j < 5; ++j)
{
group.Add(new ListViewEntry { Number = i * 5 + j });
}

_groups.Add(group);
}
}

public IReadOnlyList<ListViewGroup> Groups
{
get { return _groups; }
}
}

[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 5184, "Items get mixed up when fast scrolling", PlatformAffected.Android)]
public class Issue5184 : TestContentPage
{
protected override void Init()
{
BindingContext = new MainPageViewModel();
var listView = new ListView
{
Margin = 20,
IsGroupingEnabled = true,
GroupHeaderTemplate = new DataTemplate(() =>
{
var label = new Label();
label.SetBinding(Label.TextProperty, nameof(ListViewGroup.Heading));
var grid = new Grid {
HorizontalOptions = LayoutOptions.FillAndExpand,
ColumnDefinitions = new ColumnDefinitionCollection {
new ColumnDefinition { Width = GridLength.Star }
},
Children = { label }
};
return new ViewCell { View = grid };
}),
ItemTemplate = new DataTemplate(() =>
{
var label = new Label();
label.SetBinding(Label.TextProperty, nameof(ListViewEntry.Number));
var grid = new Grid
{
HorizontalOptions = LayoutOptions.FillAndExpand,
ColumnDefinitions = new ColumnDefinitionCollection {
new ColumnDefinition { Width = GridLength.Star }
},
Children = { label }
};
return new ViewCell { View = grid };
})
};
listView.SetBinding(ListView.ItemsSourceProperty, nameof(MainPageViewModel.Groups));

Content = new StackLayout
{
Children = {
new Label { Text = "Quickly scroll down and back. Check that all items are correct." },
listView
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue2617.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3139.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3087.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1760_1.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1332.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5184.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3089.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1342.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2482.cs" />
Expand Down
4 changes: 2 additions & 2 deletions Xamarin.Forms.Core/Layout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ protected void UpdateChildrenLayout()
for (var i = 0; i < LogicalChildrenInternal.Count; i++)
CompressedLayout.SetHeadlessOffset((VisualElement)LogicalChildrenInternal[i], isHeadless ? new Point(headlessOffset.X + Bounds.X, headlessOffset.Y + Bounds.Y) : new Point());

_lastLayoutSize = new Size(width, height);

LayoutChildren(x, y, w, h);

for (var i = 0; i < oldBounds.Length; i++)
Expand All @@ -273,8 +275,6 @@ protected void UpdateChildrenLayout()
return;
}
}

_lastLayoutSize = new Size(width, height);
}

internal static void LayoutChildIntoBoundingRegion(View child, Rectangle region, SizeRequest childSizeRequest)
Expand Down
8 changes: 8 additions & 0 deletions Xamarin.Forms.Platform.Android/VisualElementTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ public void UpdateLayout()
//On Width or Height changes, the anchors needs to be updated
UpdateAnchorX();
UpdateAnchorY();

MaybeRequestLayout();
}

void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
Expand All @@ -130,6 +132,12 @@ void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
return;
}

if (e.Is(Platform.RendererProperty))
{
_renderer.View.Invalidate();
return;
}

if (_renderer.Element.Batched)
{
if (e.PropertyName == VisualElement.XProperty.PropertyName || e.PropertyName == VisualElement.YProperty.PropertyName || e.PropertyName == VisualElement.WidthProperty.PropertyName ||
Expand Down

0 comments on commit df113d9

Please sign in to comment.