xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

[Bug] Xamarin.Forms issue with control colors on appearing #14740

Open ShadowOfPhantom opened 3 years ago

ShadowOfPhantom commented 3 years ago

Some elements are changing its colors on appearing with Xamarin.Forms 5.0.0.2125. It works well with previous version 5.0.0.2083. Looks like something is broken, please check this out

Videos are attached below

Workaround

Downgrade to 5.0.0.2083

https://user-images.githubusercontent.com/41395390/137596968-6a07d30e-e374-45b6-a573-512bdd48d2ff.MOV

https://user-images.githubusercontent.com/41395390/137596969-96e2cd76-79a7-47c2-b658-ebf90ad9606d.MOV

https://user-images.githubusercontent.com/41395390/137596972-f90214c1-61c1-4c1d-a707-a6db24462ede.MOV

@jsuarezruiz

Could you attach a small sample where reproduce the issue?. Or, could you share more info?. The views where the issue happens, are Frames?, are you using Shell or a FlyoutPage?

Sample: ControlColorsIssue.zip

I was unable to reproduce this issue with Shell, looks like Shell is a workaround. But I have an app without FlyoutPage or shell and there is the same issue. This happens for both BoxView and frame, I attached a video sample of attached project, please take a look

https://user-images.githubusercontent.com/41395390/137795836-9115f0da-96eb-4bd9-b8e3-fea69a9e3c0b.MOV

jsuarezruiz commented 3 years ago

@ShadowOfPhantom Could you attach a small sample where reproduce the issue?. Or, could you share more info?. The views where the issue happens, are Frames?, are you using Shell or a FlyoutPage?

ShadowOfPhantom commented 3 years ago

@ShadowOfPhantom Could you attach a small sample where reproduce the issue?. Or, could you share more info?. The views where the issue happens, are Frames?, are you using Shell or a FlyoutPage?

Hi! I edited the topic with new info

jsuarezruiz commented 3 years ago

@ShadowOfPhantom Thanks for the attached sample. I am going to review it.

jsuarezruiz commented 3 years ago

Mnn, the behavior is different between the sample: frame-issue-1

And testing the same code with the latest 5.0.0 Xamarin.Forms branch: frame-issue-2

We need to review also this differences.

DouglasGiovanella commented 2 years ago

I'm also facing this problem, on 5.0.0.2083 works fine, but updating to 5.0.0.2125 or newer this issue starts to happen when setting a page on the Flyout detail.

@jsuarezruiz running the sample provided by @ShadowOfPhantom i was able to reproduce, but was hard to notice and only happens a few times. I took the liberty to change a few things in it to be more easy to reproduce:

https://user-images.githubusercontent.com/15790575/144297621-5e8c31b9-7b41-4d8d-a9b2-7031669f24b4.mov

ControlColorsIssue.zip

DouglasGiovanella commented 2 years ago

Well, after some digging i track this issue to the BoxView after the changes on this PR: https://github.com/xamarin/Xamarin.Forms/pull/11812/files and maybe it is related to https://github.com/xamarin/Xamarin.Forms/issues/14970.

I had a fews problems running the XF project on my Mac, so i couldn't test some fix alternatives and submit a PR.

@jsuarezruiz @jfversluis This issue could be prioritized to the next service release? Since i didn't find any workaround for this, its blocking us to update the XF to its latest version 😞

jfversluis commented 2 years ago

Thanks for the investigation on this! Can't make promises on prioritizing, but we'll look into it :)

ShadowOfPhantom commented 2 years ago

The same with navbar if I define Style via App.xaml instead of styles.xml of Android project. I attached a video

<Style TargetType="NavigationPage">
                <Setter Property="BackgroundColor" Value="{StaticResource MainColor}" />
                <Setter Property="BarBackgroundColor" Value="{StaticResource LightPink}" />
            </Style>

Also it doesn't flicker if I set color like this:

MainPage = new NavigationPage(new TabbedView())
            {
                BarBackgroundColor = Color.LightPink,
            };

https://user-images.githubusercontent.com/41395390/165602910-4f1d03f2-6606-4024-8390-cdd507dd5551.MOV

DouglasGiovanella commented 2 years ago

After a fews tests, looks like this issue is related to the GradientStrokeDrawable, more precisely on the draw method.

protected override void OnDraw(Shape shape, Canvas canvas, Paint paint)
{
    base.OnDraw(shape, canvas, paint);

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

    if (_strokePaint.StrokeWidth > 0)
        shape.Draw(canvas, _strokePaint);
}

The call for base.OnDraw(shape, canvas, paint); its draws the view with a black backgound because the Paint color its not set already. Moving the setter paint.Color = _backgroundColor.Value before the base call seems to solve this issue, but i dont know the real impact of doing this.

As a workaround for the boxView problem, i solved by making a custom renderer for the boxView thats forces the right color on the GradientStrokeDrawable Paint:

[assembly: ExportRenderer(typeof(BoxView), typeof(BoxViewRenderer))]
namespace Test.Droid.Renderers {
    public class BoxViewRenderer : BoxRenderer {
        public BoxViewRenderer(Context context) : base(context) { }

        protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e) {
            base.OnElementChanged(e);
            BlackBackgroundWorkaround();
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
            base.OnElementPropertyChanged(sender, e);

            string[] propsToUpdateBackground = {
                VisualElement.BackgroundColorProperty.PropertyName,
                VisualElement.BackgroundProperty.PropertyName,
                BoxView.ColorProperty.PropertyName,
                BoxView.CornerRadiusProperty.PropertyName
            };

            if (propsToUpdateBackground.Contains(e.PropertyName)) {
                BlackBackgroundWorkaround();
            }
        }

        // https://github.com/xamarin/Xamarin.Forms/issues/14740
        private void BlackBackgroundWorkaround() {
            try {
                if (Element.CornerRadius == default) return;

                FieldInfo fieldInfo =
                    typeof(BoxRenderer).GetField("_backgroundDrawable", BindingFlags.NonPublic | BindingFlags.Instance);

                if (fieldInfo != null) {
                    GradientStrokeDrawable gradientStrokeDrawable = fieldInfo.GetValue(this) as GradientStrokeDrawable;

                    AndroidColor? gradientColor = gradientStrokeDrawable?.GetColor();
                    if (gradientColor.HasValue) gradientStrokeDrawable.Paint.Color = gradientColor.Value;
                }
            } catch (Exception e) {
                // something is wrong
            }
        }
    }
}