When I define a Custom Renderer of StackLayout , the BackgroundColor in xaml doesn't work any more (it is always transparent) . The issue is only exists in iOS .As a workaround , I have to rewrite the method SetBackgroundColor
in the Custom Renderer .
protected override void SetBackgroundColor(Color color)
{
base.SetBackgroundColor(color);
if (NativeView == null)
return;
if (color != Color.Default)
NativeView.BackgroundColor = color.ToUIColor();
}
Hi @luczha thanks for the report!
Is there any reason that you are not following the bug template we have in place? Because now I am missing some important information!
Is this also happening on Android? Which version of Xamarin.Forms are you using? Which version of iOS did you test this on? Would you happen to have a small reproduction sample that shows this behavior?
Thanks!
The issue only appears in iOS 13.3 , in Android it works fine . I don't make sure if it exists before iOS 13.0 . You could define a StackLayout and set the BackgroungColor . Then , create the custom renderer in iOS project . And if you debug it you will see the effect .
Unfortunately, it's not that simple to reproduce.
I have this File > New App and added a background color and a custom renderer.
<StackLayout BackgroundColor="Red">
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
</StackLayout>
Which works without any problems on iOS 13, using Xamarin.Forms 4.5 latest stable. You can find my project attached. Please add to this the specifics for your project which shows this bug.
Allow me to chime in. I opened a StackOverflow question first regarding this issue because I figured I might be doing something wrong instead of this being a bug. You can find more information on that here.
The use case is actually a bit different, I declared a custom renderer like this:
public class MyCustomStackLayout : StackLayout { }
public class MyCustomStackLayoutRenderer : ViewRenderer<MyCustomStackLayout, UIView>
{
protected override void OnElementChanged(ElementChangedEventArgs<ExportableStackLayout> e)
{
base.OnElementChanged(e);
// some customizations here that don't mess with BackgroundColor at all
// removing all customizations doesn't fix the issue either.
}
}
And used it like this:
<custom:MyCustomStackLayout BackgroundColor="Green">
</custom:MyCustomStackLayout>
I think you are simply using the wrong base class. When I do this
public class StackLayoutCustomRenderer : VisualElementRenderer<MyCustomStackLayout>
{
protected override void OnElementChanged(ElementChangedEventArgs<MyCustomStackLayout> e)
{
base.OnElementChanged(e);
// some customizations here that don't mess with BackgroundColor at all
// removing all customizations doesn't fix the issue either.
}
}
Things work as expected. Find the updated code attached.
Thanks! I figured it might be the wrong renderer, which leads me to another question: what is the easiest way to find the correct base renderer? I tried finding myself around the codebase, but as I said in the SO question, StackLayout
, like some other classes, are not declared in the AssemblyInfo.
Also, the documentation tells me that I should be using ViewRenderer
instead of VisualElementRenderer
, as stated here. In fact, looking at the class hierarchy, ViewRenderer
extends VisualElementRenderer
, which also leads me to believe that I should be inheriting from ViewRenderer
, which should be more specific and more complete.
From this experience, I think the docs are not clear enough regarding this topic, because, as you can see, I couldn't figure out how I could correctly extend a StackLayout
(and it would probably happen with other layouts too) by reading the docs AND looking at the code .
What do you think? Am I missing something or is this something that should be improved in the docs?
Taking a closer look at the code and the difference between the two renderers, I couldn't figure out why ViewRenderer
doesn't set the BackgroundColor at the constructor, like VisualElementRenderer
does. The base constructors isn't called from ViewRenderer
either, and there is a guard that will prevent ViewRenderer
from updating the BackgroundColor at the first rendering.
This is all very confusing and seems VERY specific to BackgroundColor. I know changing this behavior now would be a breaking change, and probably wouldn't happen, but do you have any info on why that was written like that in the first place? Or is this something that you would consider a bug?
@akamud I'm guessing that guard is there so it only runs when the renderer is reused which is only really the case with CollectionView and ListView so that when a new element comes in the background is updated
AFAIR you can't really create a custom renderer for stacklayout, grid, etc... because these are all just xplat layouts. They don't have any specific platform level representations. All they do is define the bounds of the elements they contain and then those bounds get projected to the platform.
i'm not sure your use case but you'd probably want to create a custom renderer for a customview instead of a stacklayout or a contentview where the contents is a stacklayout
I guess it makes sense for my use case. Just wondering if this recommendation of not creating a custom renderer for layouts should be added to the docs. What do you think @PureWeen?
Also, what is the easiest way of finding the Renderers for those classes missing from AssemblyInfo
?
Would this page in the docs be of any help?
Kind of.
Using it as a way of finding the missing classes from AssemblyInfo
definitely helps. But, as I commented above, I did use it, and it doesn't say anything about extending from these layouts not being a good idea, so it kind of led me to the wrong solution. Maybe adding a warning would be good enough.
We'll consider adding that warning. Thanks!