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

[iOS] Fix wrong gray color using transparent in iOS gradients #17696

Merged
merged 10 commits into from
Dec 20, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@
<Label
Text="Background" />
</Frame>
<Label
Text="Background (Gradient using a transparent color)"
Style="{StaticResource Headline}"/>
<Frame>
<Frame.Background>
<LinearGradientBrush
StartPoint="0,0"
EndPoint="0,1">
<GradientStop
Color="Transparent"
Offset="0.0"/>
<GradientStop
Color="Red"
Offset="1.00"/>
</LinearGradientBrush>
</Frame.Background>
<Label
Text="Background" />
</Frame>
<Label
Text="BorderColor"
Style="{StaticResource Headline}"/>
Expand Down Expand Up @@ -134,8 +153,7 @@
Margin="10">
<!-- Empty on purpose -->
</Frame>
</Grid>

</Grid>
</VerticalStackLayout>
</ScrollView>
</views:BasePage.Content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,11 @@ public virtual void SetupLayer()
if (backgroundLayer != null)
{
_actualView.Layer.BackgroundColor = UIColor.Clear.CGColor;
Layer.InsertBackgroundLayer(backgroundLayer, 0);

backgroundLayer.BackgroundColor = ColorExtensions.BackgroundColor.CGColor;
backgroundLayer.CornerRadius = cornerRadius;

Layer.InsertBackgroundLayer(backgroundLayer, 0);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static CALayer GetBackgroundLayer(this UIView control, Brush brush)
if (linearGradientBrush.GradientStops != null && linearGradientBrush.GradientStops.Count > 0)
{
var orderedStops = linearGradientBrush.GradientStops.OrderBy(x => x.Offset).ToList();
linearGradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray();
linearGradientLayer.Colors = GetCAGradientLayerColors(orderedStops);
linearGradientLayer.Locations = GetCAGradientLayerLocations(orderedStops);
}

Expand Down Expand Up @@ -100,7 +100,7 @@ public static CALayer GetBackgroundLayer(this UIView control, Brush brush)
if (radialGradientBrush.GradientStops != null && radialGradientBrush.GradientStops.Count > 0)
{
var orderedStops = radialGradientBrush.GradientStops.OrderBy(x => x.Offset).ToList();
radialGradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray();
radialGradientLayer.Colors = GetCAGradientLayerColors(orderedStops);
radialGradientLayer.Locations = GetCAGradientLayerLocations(orderedStops);
}

Expand Down Expand Up @@ -251,6 +251,31 @@ static NSNumber[] GetCAGradientLayerLocations(List<GradientStop> gradientStops)
}
}

static CGColor[] GetCAGradientLayerColors(List<GradientStop> gradientStops)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are mostly pending changes from xamarin/Xamarin.Forms#13401

Copy link
Member

Choose a reason for hiding this comment

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

Should this rather be a reference to the code in Core? Instead of a duplicate? Might be possible if the method was internal.

{
if (gradientStops == null || gradientStops.Count == 0)
return new CGColor[0];

CGColor[] colors = new CGColor[gradientStops.Count];

int index = 0;
foreach (var gradientStop in gradientStops)
{
if (gradientStop.Color == Colors.Transparent)
{
var color = gradientStops[index == 0 ? index + 1 : index - 1].Color;
CGColor nativeColor = color.ToPlatform().ColorWithAlpha(0.0f).CGColor;
colors[index] = nativeColor;
}
else
colors[index] = gradientStop.Color.ToCGColor();

index++;
}

return colors;
}

static bool ShouldUseParentView(UIView view)
{
if (view is UILabel)
Expand Down
29 changes: 27 additions & 2 deletions src/Core/src/Graphics/PaintExtensions.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static partial class PaintExtensions
if (linearGradientPaint.GradientStops != null && linearGradientPaint.GradientStops.Length > 0)
{
var orderedStops = linearGradientPaint.GradientStops.OrderBy(x => x.Offset).ToList();
linearGradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray();
linearGradientLayer.Colors = GetCAGradientLayerColors(orderedStops);
linearGradientLayer.Locations = GetCAGradientLayerLocations(orderedStops);
}

Expand All @@ -96,7 +96,7 @@ public static partial class PaintExtensions
if (radialGradientPaint.GradientStops != null && radialGradientPaint.GradientStops.Length > 0)
{
var orderedStops = radialGradientPaint.GradientStops.OrderBy(x => x.Offset).ToList();
radialGradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray();
radialGradientLayer.Colors = GetCAGradientLayerColors(orderedStops);
radialGradientLayer.Locations = GetCAGradientLayerLocations(orderedStops);
}

Expand Down Expand Up @@ -165,5 +165,30 @@ static NSNumber[] GetCAGradientLayerLocations(List<PaintGradientStop> gradientSt
return locations;
}
}

static CGColor[] GetCAGradientLayerColors(List<PaintGradientStop> gradientStops)
{
if (gradientStops == null || gradientStops.Count == 0)
return new CGColor[0];

CGColor[] colors = new CGColor[gradientStops.Count];

int index = 0;
foreach (var gradientStop in gradientStops)
{
if (gradientStop.Color == Colors.Transparent)
{
var color = gradientStops[index == 0 ? index + 1 : index - 1].Color;
Copy link
Member

Choose a reason for hiding this comment

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

What happens if there are multiple transparent together? trans at 0, trans at 0.3 and then red at 1? Also, what happens if the transparent is between two colors? red, trans, green.

nit: this feels like a for loop instead of foreach. I personally don't like the rando index variable outside the loop. But I am also just weird.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a new sample and a new Device Test to validate that case:
image

CGColor nativeColor = color.ToPlatform().ColorWithAlpha(0.0f).CGColor;
colors[index] = nativeColor;
}
else
colors[index] = gradientStop.Color.ToCGColor();

index++;
}

return colors;
}
}
}