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

[Android] Update gradients based on offset changes in Frame and BoxView #11812

Merged
merged 2 commits into from
Sep 6, 2021
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,96 @@
<?xml version="1.0" encoding="utf-8" ?>
<controls:TestContentPage
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Issue 11795"
x:Class="Xamarin.Forms.Controls.Issues.Issue11795">
<controls:TestContentPage.Resources>
<ResourceDictionary>

<LinearGradientBrush x:Key="LinearBrush" StartPoint="0, 0" EndPoint="1, 0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="YellowGreen" Offset="0.1"/>
<GradientStop Color="Green" Offset="0.9"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>

<Style TargetType="Slider">
<Setter Property="MinimumTrackColor" Value="LightGray" />
<Setter Property="MaximumTrackColor" Value="Gray" />
</Style>

</ResourceDictionary>
</controls:TestContentPage.Resources>
<StackLayout>
<Label
Padding="12"
BackgroundColor="Black"
TextColor="White"
Text="Modify the Brush Offset values. If you modify the gradient, the test has passed."/>
<Grid>
<!-- EXPLORER -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Grid.Row="0"
Margin="12, 0"
Padding="12">
<Label
Text="BoxView"/>
<BoxView
x:Name="GradientBoxView"
HeightRequest="120"
WidthRequest="120"
CornerRadius="12"
Background="{StaticResource LinearBrush}"/>
<Label
Text="Frame"/>
<Frame
x:Name="GradientFrame"
HasShadow="True"
HeightRequest="120"
WidthRequest="120"
CornerRadius="12"
Background="{StaticResource LinearBrush}">
<Grid>
<Label
HorizontalOptions="Center"
VerticalOptions="Center"
Text="LinearGradientBrush"/>
</Grid>
</Frame>
</StackLayout>
<ScrollView
Grid.Row="1"
Margin="12, 0"
Padding="12">
<StackLayout>
<Label
Text="Color 1 Offset"/>
<Slider
x:Name="Offset1Slider"
Minimum="0.0"
Maximum="1.0"
Value="0.1"
ValueChanged="OnOffset1SliderValueChanged"/>
<Label
Text="Color 2 Offset"/>
<Slider
x:Name="Offset2Slider"
Minimum="0.0"
Margin="1.0"
Value="0.9"
ValueChanged="OnOffset2SliderValueChanged"/>
</StackLayout>
</ScrollView>
</Grid>
</Grid>
</StackLayout>
</controls:TestContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml;

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

namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.Brush)]
#endif
#if APP
[XamlCompilation(XamlCompilationOptions.Compile)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 11795, "[Bug] Brushes API - gradient offset does nothing on Android", PlatformAffected.Android)]
public partial class Issue11795 : TestContentPage
{
#if APP
float _offset1, _offset2;
#endif
public Issue11795()
{
#if APP
Title = "Issue 11795";
InitializeComponent();

_offset1 = 0.1f;
_offset2 = 0.9f;
#endif
}

protected override void Init()
{

}

#if APP
void OnOffset1SliderValueChanged(object sender, ValueChangedEventArgs e)
{
_offset1 = (float)e.NewValue;
UpdateBackground(_offset1, _offset2);
}

void OnOffset2SliderValueChanged(object sender, ValueChangedEventArgs e)
{
_offset2 = (float)e.NewValue;
UpdateBackground(_offset1, _offset2);
}

void UpdateBackground(float offset1, float offset2)
{
LinearGradientBrush linearGradient = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0),
GradientStops = new GradientStopCollection
{
new GradientStop { Color = Color.YellowGreen, Offset = offset1 },
new GradientStop { Color = Color.Green, Offset = offset2 }
}
};

GradientBoxView.Background = linearGradient;
GradientFrame.Background = linearGradient;
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue12150.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12590.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13726.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11795.xaml.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
Expand Down Expand Up @@ -2206,6 +2207,9 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue13726.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue11795.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla27417Xaml.xaml">
Expand Down
14 changes: 8 additions & 6 deletions Xamarin.Forms.Material.Android/MaterialFrameRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

using System;
using System;
using System.ComponentModel;
using Android.Content;
using Android.Graphics.Drawables;
using Android.Graphics.Drawables.Shapes;
using Android.Views;
using AndroidX.Core.View;
using Xamarin.Forms.Platform.Android;
Expand All @@ -29,7 +29,7 @@ public class MaterialFrameRenderer : MaterialCardView,
readonly EffectControlProvider _effectControlProvider;
readonly MotionEventHelper _motionEventHelper;
Drawable _defaultBackgroundDrawable;
GradientDrawable _backgroundGradientDrawable;
GradientStrokeDrawable _backgroundGradientDrawable;

public MaterialFrameRenderer(Context context)
: base(MaterialContextThemeWrapper.Create(context))
Expand Down Expand Up @@ -265,11 +265,13 @@ void UpdateBackground()
if (_defaultBackgroundDrawable == null)
_defaultBackgroundDrawable = Background;

_backgroundGradientDrawable = new GradientDrawable();
_backgroundGradientDrawable.SetShape(ShapeType.Rectangle);
_backgroundGradientDrawable = new GradientStrokeDrawable
{
Shape = new RectShape()
};

_backgroundGradientDrawable.SetCornerRadius(Radius);
_backgroundGradientDrawable.UpdateBackground(bgBrush, Height, Width);
_backgroundGradientDrawable.UpdateBackground(bgBrush);

Background = _backgroundGradientDrawable;
}
Expand Down
27 changes: 27 additions & 0 deletions Xamarin.Forms.Platform.Android/Extensions/BrushExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,22 @@ public static void UpdateBackground(this GradientDrawable gradientDrawable, Brus
}
}

public static void UpdateBackground(this GradientStrokeDrawable gradientStrokeDrawable, Brush brush)
{
if (gradientStrokeDrawable == null || brush == null || brush.IsEmpty)
return;

gradientStrokeDrawable.SetStroke(0, Color.Default.ToAndroid());

if (brush is SolidColorBrush solidColorBrush)
{
var color = solidColorBrush.Color.IsDefault ? Color.Default.ToAndroid() : solidColorBrush.Color.ToAndroid();
gradientStrokeDrawable.SetColor(color);
}
else
gradientStrokeDrawable.SetGradient(brush);
}

public static bool UseGradients(this GradientDrawable gradientDrawable)
{
if (!Forms.IsNougatOrNewer)
Expand All @@ -179,6 +195,17 @@ public static bool UseGradients(this GradientDrawable gradientDrawable)
return colors != null && colors.Length > 1;
}

public static bool UseGradients(this GradientStrokeDrawable gradientDrawable)
{
if (!Forms.IsNougatOrNewer)
return false;

var color = gradientDrawable.GetColor();
var shaderFactory = gradientDrawable.GetShaderFactory();

return color != null || shaderFactory != null;
}

internal static bool IsValidGradient(GradientStopCollection gradients)
{
if (gradients == null || gradients.Count == 0)
Expand Down
40 changes: 23 additions & 17 deletions Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.ComponentModel;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Graphics.Drawables.Shapes;
using Android.Views;
using AndroidX.CardView.Widget;
using AndroidX.Core.View;
Expand All @@ -22,7 +22,7 @@ public class FrameRenderer : CardView, IVisualElementRenderer, IViewRenderer, IT
bool _hasLayoutOccurred;
bool _disposed;
Frame _element;
GradientDrawable _backgroundDrawable;
GradientStrokeDrawable _backgroundDrawable;

VisualElementPackager _visualElementPackager;
VisualElementTracker _visualElementTracker;
Expand Down Expand Up @@ -176,8 +176,10 @@ protected virtual void OnElementChanged(ElementChangedEventArgs<Frame> e)
if (e.NewElement != null)
{
this.EnsureId();
_backgroundDrawable = new GradientDrawable();
_backgroundDrawable.SetShape(ShapeType.Rectangle);
_backgroundDrawable = new GradientStrokeDrawable
{
Shape = new RectShape()
};
this.SetBackground(_backgroundDrawable);

if (_visualElementTracker == null)
Expand Down Expand Up @@ -291,28 +293,32 @@ void UpdateBackground()
if (_disposed)
return;

Brush background = Element.Background;

if (Brush.IsNullOrEmpty(background))
if (_backgroundDrawable.UseGradients())
{
if (_backgroundDrawable.UseGradients())
_backgroundDrawable.Dispose();
_backgroundDrawable = null;
this.SetBackground(null);

_backgroundDrawable = new GradientStrokeDrawable
{
_backgroundDrawable.Dispose();
_backgroundDrawable = null;
this.SetBackground(null);
Shape = new RectShape()
};

_backgroundDrawable = new GradientDrawable();
_backgroundDrawable.SetShape(ShapeType.Rectangle);
this.SetBackground(_backgroundDrawable);
}
this.SetBackground(_backgroundDrawable);
UpdateBorderColor();
UpdateCornerRadius();
}

Brush background = Element.Background;

if (Brush.IsNullOrEmpty(background))
UpdateBackgroundColor();
}
else
{
_height = Control.Height;
_width = Control.Width;
_backgroundDrawable.UpdateBackground(background, _height, _width);

_backgroundDrawable.UpdateBackground(background);
}
}

Expand Down
16 changes: 13 additions & 3 deletions Xamarin.Forms.Platform.Android/GradientStrokeDrawable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Xamarin.Forms.Platform.Android
public class GradientStrokeDrawable : PaintDrawable
{
readonly Paint _strokePaint;
AColor _backgroundColor;
AColor? _backgroundColor;

public GradientStrokeDrawable()
{
Expand All @@ -27,6 +27,14 @@ public void SetColor(AColor backgroundColor)
InvalidateSelf();
}

public AColor? GetColor()
{
if (_backgroundColor.HasValue)
return _backgroundColor.Value;

return null;
}

public void SetStroke(int strokeWidth, AColor strokeColor)
{
_strokePaint.StrokeWidth = strokeWidth;
Expand All @@ -36,6 +44,8 @@ public void SetStroke(int strokeWidth, AColor strokeColor)

public void SetGradient(Brush brush)
{
_backgroundColor = null;

if (brush is LinearGradientBrush linearGradientBrush)
{
var p1 = linearGradientBrush.StartPoint;
Expand Down Expand Up @@ -74,8 +84,8 @@ protected override void OnDraw(Shape shape, Canvas canvas, Paint paint)
{
base.OnDraw(shape, canvas, paint);

if (_backgroundColor != null)
paint.Color = _backgroundColor;
if (_backgroundColor.HasValue)
paint.Color = _backgroundColor.Value;

shape.Draw(canvas, _strokePaint);
}
Expand Down
Loading