rotorgames / Rg.Plugins.Popup

Xamarin Forms popup plugin
MIT License
1.15k stars 337 forks source link

Popup page flickers on appearing #711

Open lassana opened 2 years ago

lassana commented 2 years ago

🐛 Bug Report

If the popup page has a ListView in its content, and ItemsSource of that ListView gets set in OnSizeAllocated() or OnAppearingAnimationBegin, the appearing animation gets broken and the page flickers: at first the page is shown in the center of the screen for a short moment, and then the actual animation starts. The behavior is pretty much the same as in #404

It can be reproduced with the latest X.F 5.0.0.2196 and Rg.Plugins.Popup 2.0.0.14.

The reproduction sample: RgPopupAppearingBug.zip

    public class BuggedPopup : PopupPage
    {
        private readonly ListView _listView;
        private bool _isInitialized;

        public BuggedPopup()
        {
            CloseWhenBackgroundIsClicked = false;

            Animation = new MoveAnimation
            {
                PositionIn = MoveAnimationOptions.Bottom,
                PositionOut = MoveAnimationOptions.Bottom,
                DurationIn = 400,
                DurationOut = 300,
                EasingIn = Easing.SinOut,
                EasingOut = Easing.SinIn,
                HasBackgroundAnimation = true
            };

            _listView = new ListView(ListViewCachingStrategy.RecycleElementAndDataTemplate)
            {
                BackgroundColor = Color.Transparent,
                HasUnevenRows = true,
                ItemTemplate = new DataTemplate(() =>
                {
                    var label = new Label();
                    label.FontAttributes = FontAttributes.Bold;
                    label.SetBinding(Label.TextProperty, new Binding("."));
                    return new ViewCell
                    {
                        View = label
                    };
                })
            };

            Content = new Frame
            {
                HeightRequest = 300,
                WidthRequest = 500,
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                BorderColor = Color.Red,
                Content = new StackLayout
                {
                    Orientation = StackOrientation.Vertical,
                    Children =
                    {
                        new Button
                        {
                            Text = "Close",
                            Command = new Command(() => this.Navigation.PopPopupAsync())
                        },
                        _listView
                    }
                }
            };
        }

        protected override void OnAppearingAnimationBegin()
        {
            if (!_isInitialized)
            {
                /*
                 * This is the key place.
                 * 
                 * Setting ItemsSource in OnSizeAllocated or OnAppearingAnimationBegin
                 * breaks the appearing animation.
                 */
                _isInitialized = true;
                _listView.ItemsSource = Enumerable.Repeat(
                    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
                    30)
                    .ToList();
            }
            base.OnAppearingAnimationBegin();
        }
    }

https://user-images.githubusercontent.com/2004960/138688360-3120e2f5-fb5b-4203-a683-588dc5d5b21a.mp4

Expected behavior

The page appearing animation is smooth.

Reproduction steps

Open attached project, run, and click "Show Popup".

Configuration

Version: 2.0.0.14

Platform:

brandonward34 commented 2 years ago

I am also experiencing this issue

Suplanus commented 2 years ago

Same here, was also in 2.0.0.13.

brandonward34 commented 2 years ago

Any update on this? we have users reporting this happens quite frequently now... Ive started looking into a little more and seems like it has something to do with this line taskList.Add(content.TranslateTo(_defaultTranslationX, _defaultTranslationY, DurationIn, EasingIn)); seems similar to issue #404

ShadowOfPhantom commented 2 years ago

Same here guys

rjhind commented 2 years ago

Yep, I see this also. Happens on all my popups, not just those with ListViews.

rjhind commented 2 years ago

Has anyone been able to solve this? This happens on every popup for us. Thanks.

brandonward34 commented 2 years ago

Still happening on 2.1.0 as well, just an FYI

brunonocetti commented 2 years ago

any workaround?

bradencohen commented 2 years ago

Any update on a fix for this? I took an approach of overriding the MoveAnimation and adding a Task.Delay to the OnAppearing and it didn't seem to help. Pretty annoying bug that takes away a clean user-experience.

donatellijl commented 1 year ago

I am having this issue as well. Has anyone migrated to a different nuget due to this issue?

ShadowOfPhantom commented 1 year ago

I am having this issue as well. Has anyone migrated to a different nuget due to this issue?

You don't really have to use this plugin, just remove it from your solution and make the same functionality with only xamarin

jlbeard84 commented 1 year ago

I had the same problem here - iOS would flicker not on every popup, but maybe 1 out of every 3 or so. The approach that I took was to extend the animation class we are using to be a custom animation:

public class SystemDialogAnimation: MoveAnimation

The thing you need to change is in the Appearing method, so if you override that and set another task to update opacity, you can avoid the flicker. I think the issue happens where timing can be out of order, so a call to make the page visible happens right before the call to execute the animation, resulting in a couple of frames where the popup is visible in the initial position.

public override Task Appearing(View content, PopupPage page)
{
    var taskList = new List<Task>
    {
        base.Appearing(content, page)
    };

    if (content != null)
    {
        // set initial opacity
        page.Opacity = 0;

        var topOffset = GetTopOffset(content, page);
        var leftOffset = GetLeftOffset(content, page);

        if (PositionIn == MoveAnimationOptions.Top)
        {
            content.TranslationY = -topOffset;
        }
        else if (PositionIn == MoveAnimationOptions.Bottom)
        {
            content.TranslationY = topOffset;
        }
        else if (PositionIn == MoveAnimationOptions.Left)
        {
            content.TranslationX = -leftOffset;
        }
        else if (PositionIn == MoveAnimationOptions.Right)
        {
            content.TranslationX = leftOffset;
        }

        // quickly make the page opaque to cover up the misplaced frames
        taskList.Add(page.FadeTo(100, 1));
        taskList.Add(content.TranslateTo(_defaultTranslationX, _defaultTranslationY, DurationIn, EasingIn));
    }

    ShowPage(page);

    return Task.WhenAll(taskList);
}

I'll create a PR to hopefully get this pulled in, but in the meantime this might be able to get you by.

bradencohen commented 1 year ago

@jlbeard84 works like a charm, thanks!

derekvantonder commented 1 year ago

@jlbeard84 you're such a bro, I implemented this and it works. It's still required even with v2.1 NuGet package.

tataroch-ka commented 5 months ago

@jlbeard84 thank u