0

I have a custom control inherited from Frame. (In a nutshell, it's kind of a custom alert box which I show over the whole app content).

I am using Custom Renderer to achieve this. In xaml the control is located directly on the page (among other controls) (actually, I am creating it in the condebehind, but that makes no difference). (Implementing it for iOS so far only). The showing/hiding is initiated by IsVisible XF property. Then, I am adding the container view (native one) into the root of the app.

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "IsVisible")
        {
            // showing/hiding here

I am having two issues in this situation: 1. Right on this event raising the content positioning of the native view generated is not quite initialized: the iOS Frame values of the views don't have any widths/heights setup. That all probably done right after, so what I do is the following:

                Task.Run(async () =>
                {
                    await Task.Delay(10);
                    InvokeOnMainThread(() =>
                    {
                        SetupLayout();
                        Subviews[0].Alpha = 1;
                        SetupAnimationIn();
                    });
                });

... which generally works, but still not quite slightly, and the approach is neither reliable nor nice.

  1. On IsVisible = false it's even worse: I cannot handle the leaving animation as the element content got destroyed by XF engine (I suppose) right after (or even before) the notification raised, so the element disappears instantly, which doesn't look nice for the user experience.

So, is there any nice way to handle those things?

Agat
  • 4,577
  • 2
  • 34
  • 62

1 Answers1

0

It's probably a little late, but I thought I would offer some guidance for anyone else trying to do something similar. For (1) I'm not quite sure what you mean that the native view is not quite initialized, but here is something you might find useful:

var measurement = Measure(screenWidth, screenHeight);
var contentHeight = measurement.Request.Height;

You can read more about what the 'Measure' method does in the docs, but basically it gives you the minimum dimensions of the view element based on its content. The arguments are constraints, so use the maximum size that the view might be. You can use it to initialize the dimensions manually by setting 'WidthRequest' and 'HeightRequest'.

(2) Basically you need to override the IsVisible property like this:

public static new readonly BindableProperty IsVisibleProperty = BindableProperty.Create(
        nameof(IsVisible), typeof(bool), typeof(MyCustomView), default(bool), BindingMode.OneWay);
public new bool IsVisible
{
    get => (bool)GetValue(IsVisibleProperty);
    set => SetValue(IsVisibleProperty, value);
}

Note the use of the new keyword to override the inherited property. Of course, then you will need to handle the visibility yourself.

protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == IsVisibleProperty.PropertyName)
        {
            if (IsVisible) AnimateIn();
            else AnimateOut();
        }
    }

Now you can handle the visibility however you want. Hopefully this is of some help!

dzlp
  • 31
  • 1
  • 8
  • Thanks for the responses, but neither of your advice is not actually an answer. 1. The issue is that Xamarin starts "drawing" the control, thus setting up all the layouts only after IsVisible is set to "true". That means at that very moment when IsVisible is set up by "outside" code, native elements aren't rendered yet, so there is no way to animate it properly. – Agat Jan 03 '19 at 15:57
  • 2. There is no way with overriding the property and applying the animation (same way as you've mentioned). However, IsVisible still should work in natural way after that: it must remove the control (as in xaml as in Native) from controls tree. So, it still should be functioning actually as natural IsVisible property logic as well. – Agat Jan 03 '19 at 15:58
  • (1) I must not be understanding your problem correctly then. To me it sounds like you need to know the dimensions of the rendered view in order to set up your animation. If so, you should be able to use the Measure method to calculate the width and height, even if it hasn't been rendered yet. Another thing to try is check if any PropertyChangedEvents are fired after your control's dimensions are set. Then you can move your setup logic to that handler instead of the IsVisible handler. – dzlp Jan 08 '19 at 04:55
  • (2) You're right. The control I was using as a reference was being removed from the visual tree by a wrapper control. I would suggest creating your own property for managing the state of the control, and use IsVisible internally. You can then set `IsVisible` in the callback for your animation. – dzlp Jan 08 '19 at 04:56