Custom Page Transitions with Xamarin.Forms?

Is it possible to override the default Page Transitions for Xamarin.Forms when calling PushAsync or PushModalAsync?
For example, I would like to have slide or fade transitions for Android.

I have tried extending the NavigationRenderer and overriding OnPushAsync, but I can only control the animation of the pushed page and not the current page.

«1

Answers

  • rmarinhormarinho PTMember, Insider, Beta Xamurai

    Would love to know this as well.

  • ChaseFlorellChaseFlorell CAInsider, University mod

    Add me to the list. Maybe it could be a simple animation parameter?

    PushAsync(Page page) { }
    PushAsync(Page page, Animation animation) { }
    
  • MarshallMarshall USMember ✭✭

    In your pages that you are pushing onto the navigation stack, I think you could just call the Animate() function in your OnAppearing(), and implement your animation there.

  • ChaseFlorellChaseFlorell CAInsider, University mod
    edited June 2014

    ah, or pass it as a parameter... would it be something like this?

    // parent
    var animation = new Animation(); // set it up
    PushAsync(new MyCoolPage(animation));
    
    // child
    private Animation _animation;
    public MyCoolPage(Animation animation)
    {
        _animation = animation;
    }
    protected override void OnAppearing()
    {
        base.OnAppearing();
        this.Animate("anim", _animation);
    }
    
  • MarshallMarshall USMember ✭✭

    I would guess so, I haven't actually tinkered around with animation yet, but I know that's what the general logic looked like in the old xamarin

  • I tried adding Animation in OnAppearing (new page sliding in) and OnDisappearing (current page sliding out).

    public class BasePage : ContentPage
        {
            protected override void OnAppearing()
            {
                base.OnAppearing();
    
                this.Animate("", (s) => Layout(new Rectangle(((1 - s) * Width), Y, Width, Height)), 16, 600, Easing.Linear, null, null);
            }
    
            protected override void OnDisappearing()
            {
                base.OnDisappearing();
    
                this.Animate("", (s) => Layout(new Rectangle((s * Width) * -1, Y, Width, Height)), 16, 600, Easing.Linear, null, null);
            }
        }
    

    What happens is:
    Normal page transition happens and then OnAppearing animation happens. OnDisappearing fires, but the animation is not visible.

    For iOS: Current page slides out while new page slides in (default page transition), new page slides in again (OnAppearing).

    For Android: Current page disappears (default page transition), new page slides in (OnAppearing).

    I need to be able to control both the animation of the current page and the animation of the new page, OnPushAsync.

  • DerekPapworth.4183DerekPapworth.4183 GBMember ✭✭

    Plus it would be great to have an option to just turn off the default animation as with Windows Phone for instance the current animation when pushing/popping pages really slows things down .. on a previous app without animation (native) switch from one page to another is very quick but with the .Forms animation it's distinctly slower and when doing multiple page switches (i.e. from list, open form, back to list, opening another form etc) it makes the app not very user friendly speed wise .. so it'd be good to have an option to either use animation or not (bool) perhaps on the NavigationPage?

  • DavidNeubauerDavidNeubauer USMember

    I'm having the same issues with all the methods i've tried hear. The OnAppearing and OnDisappering would be great if the page didn't flicker THEN animate.

    :)

  • jeff.albanojeff.albano USMember ✭✭

    Would love to have this also. Be very useful specially to catch the user's attention. This gives the user a very good impression of the app, and its kinda cool also.

  • MichaelEngelmannMichaelEngelmann FRMember ✭✭

    I don't have a solution, but really would be a nice feature.

  • Matt.CookMatt.Cook USMember ✭✭

    I am also interested in this! It would be very useful to have some methods of animation for the different Controls.

  • CraigDunnCraigDunn USXamarin Team Xamurai

    There is no way to change the page transition animations.

    @Matt.Cook there are lots of animation methods available for individual controls. See the Xuzzle game example which animates controls around the screen.

  • DevinRoseDevinRose USMember ✭✭

    I second the desire for custom page animations.

  • JamesKiddJamesKidd AUMember

    There is support in the Android implementation the function takes a bool for animated, but its defaulted to yes in the current implementation, probably in the works though with any luck as then we can do our own custom animations

  • JamesKiddJamesKidd AUMember

    https://gist.github.com/DarkLotus/6e550c268790e2226353

    Sorry for the double post, cant edit. But I discovered you can override NavigationPage and its implementation to disable animations at-least on Android. Example code in Gist, should allow you to implement your own animations in OnAppearing

  • JoshuaNovakJoshuaNovak USMember ✭✭

    Up Vote!

  • @ChristianNormannEiland‌ :
    Although there is no smooth direct way of implementing Animation in Page Transition, your suggestion helped to some extent.
    Thanks for the Tip.

  • Hello all, It will be very much of helpful if anyone guide me on the issue-
    " How it is possible to make a content page with Left drawer and Right drawer animation while opening or closing the drawer on click of left top icon and right top icon respectively. The both icons are present at top of middle content page. And the links clicked in left or right drawer opens page in middle content page. "

    Please help me. I am stuck on this from a week. Thanks in advance

  • EricArchambaultEricArchambault USMember ✭✭

    Has anybody solved this problem. I am looking to do a custom animation from one page to another such as a fade or cross disolve.

    Thanks.

  • @CraigDunn‌ this is a thread from June, haven't the team had the time to address such a simple thing? Do you at least have a roadmap that you can share with your users? Forms lacks SEVERAL crucial features and it's really hard to use it in production without turning our code into a mess. I've asked for help on all the support channels and so far my feeling is that you gave up on Forms. Should we also give up on it?

  • alextjalextj FIMember
    edited December 2014

    @CraigDunn‌

    There is no way to change the page transition animations.

    This is one of the reasons why Xamarin.Forms should have a big red BETA sign on it. To not to fool people into thinking that it can actually be used for real world consumer application development.

  • Mark.9492Mark.9492 USMember

    Has any progress been made on this yet? This seems like a crucial missing feature.

  • Alex.litvinenkoAlex.litvinenko USMember ✭✭
    edited February 2015

    its seems it is solved in 1.3.

    await Page.Navigation.PushAsync (new AuthorizationPage (), false);

    in AuthorizationPage
    protected override void OnAppearing()
    {
    base.OnAppearing();
    this.Animate("", s => Layout (new Rectangle (((-1 + s) * Width), Y, Width, Height)), 16, 250, Easing.Linear, null, null);
    }

    for left to right sliding

  • @Alex.3651 In IOS, it shows the animation after the page was displayed completely, so it is not the way on IOS.

  • AlexLauAlexLau HKMember
    edited February 2015

    I have written a custom renderer to change the animation for iOS.

    [assembly: ExportRenderer(typeof(NavigationPage), typeof(AnimationNavigationRenderer))]
    
    class AnimationNavigationRenderer : NavigationRenderer
    {
        public override void PushViewController(UIViewController viewController, bool animated)
        {
            if (animated)
            {
                // Alternative way with different set of trannsition
                /*
                UIView.Animate(0.75, () =>
                {
                    UIView.SetAnimationCurve(UIViewAnimationCurve.EaseInOut);
                    base.PushViewController(viewController, false);
                    UIView.SetAnimationTransition(UIViewAnimationTransition.CurlUp, this.View, false);
                });
                 */
                var transition = CATransition.CreateAnimation();
                transition.Duration = 0.75;
                transition.Type = CAAnimation.TransitionPush;
    
                View.Layer.AddAnimation(transition, null);
                base.PushViewController(viewController, false);
            }
            else
            {
                base.PushViewController(viewController, false);
            }
        }
    
        public override UIViewController PopViewController(bool animated)
        {
            if (animated)
            {
                // Alternative way with different set of trannsition
                /*                UIView.Animate(0.75, () =>
                {
                    UIView.SetAnimationCurve(UIViewAnimationCurve.EaseInOut);
                    UIView.SetAnimationTransition(UIViewAnimationTransition.CurlDown, this.View, false);
                });
                */
    
                var transition = CATransition.CreateAnimation();
                transition.Duration = 0.75;
                transition.Type = CAAnimation.TransitionFromTop;
    
                View.Layer.AddAnimation(transition, null);
    
                return base.PopViewController(false);
            }
            else
            {
                return base.PopViewController(false);
            }
        }
    }
    

    https://gist.github.com/alexlau811/e12a8c126e6e082a5017

    However, it might conflict with the code above using OnAppearing and OnDisappearing (i.e. you might consider using Device.OS != TargetPlatform.iOS to bypass the code)

  • KarlKoppKarlKopp AUMember ✭✭

    @AlexLau your code just crashes my app :( I've just added the renderer to my iOS project, it compiles, but crashes on startup. Have you got a small sample app where it works, would be SUPER useful!

  • OmarSebouaiOmarSebouai USMember ✭✭

    I just succeed in implementing a Custom Animated Transition between 2 pages in iOS.

    What you need to do is to create a TransitionDelegate that you add to the page you are about to push.

    This TransitioningDelegate (UIViewControllerTransitioningDelegate) contains your GestureRecognizer.

    You should also override:

    For the animation :
    public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForPresentedController(UIViewController presented, UIViewController presenting, UIViewController source)

    For the transition :
    public override IUIViewControllerInteractiveTransitioning GetInteractionControllerForPresentation(IUIViewControllerAnimatedTransitioning animator)

    (There is also a dismissal method for both of those functions).

    In the UIViewControllerAnimatedTransitioning you create in the GetAnimationControllerForPresentedController fct (the object you return), you need to override TransitionDuration/AnimationEnded and AnimateTransition which will contains your animation.

    In the UIViewControllerInteractiveTransitioning you create in the GetInteractionControllerForPresentation fct (the object you return), you need to override StartInteractiveTransition which will contain your init for the interactive transition (start AnimateTransition and set speed/timeoffset and begintime of your layers to 0).

    Will might do an article about this because it took me almost a week to figure it out (with some help =) ). Objective-C/Swift is a pain in the *** to read :(

  • HossamHossam AUMember

    Hey,

    @SEBOUAI, Would you share the code with us?

    Did you find a solution to have custom animations transitions for Android and Windows Phone??

    Thanks

  • GustavoGalanGustavoGalan USMember ✭✭

    @AlexLauni
    The animator works perfectly in the custom renderer.

  • CristianoSantosCristianoSantos USUniversity

    I've been able to override the Navigation transitions for iOS using "UINavigationControllerDelegate".

    I uploaded a sample project with this at https://github.com/reyalpsirc/NavigationExample

    Please note that this project only works with pages that have NavigationPage.SetHasNavigationBar (this, false); and that it could still be improved (since there are some accesses to a static variable).

    At least it works and can be an example for people looking for this on iOS :)

  • AlexNAlexN RUMember ✭✭

    Guys, I had the same problem. And i wrote new control for Xamarin.Forms.
    Check out my Xamarin component 'AnimationNavigationPage': https://components.xamarin.com/view/customnavpage

    It works with all pages for iOS and Droid.

  • DeanGrimmDeanGrimm USMember

    @AlexN
    I'm working with your component, and it appears that PageAnimation is not being called on my ContentPage for iOS
    public IPageAnimation PageAnimation { get { return new SlidePageAnimation { Duration = 200, Subtype =AnimationSubtype.FromLeft }; } }

    This is working great on Android, just not on iOS

  • AlexNAlexN RUMember ✭✭
    edited March 2016

    @DeanGrimm
    Hi !

    I think you forgot this - FormsControls.Touch.Renderers.Init();

    In AppDelegate.cs
    public override bool FinishedLaunching(UIApplication app, NSDictionary options) { Xamarin.Forms.Forms.Init(); FormsControls.Touch.Renderers.Init(); LoadApplication (new App ()); return base.FinishedLaunching(app, options); }

  • DeanGrimmDeanGrimm USMember

    Working now, thanks!

  • VarunRVarunR USUniversity ✭✭

    Modal page transitions can be done by writing page renderer for the page. Here is the code i have used to accomplish the same.
    Step1 => Implement the UIViewControllerTransitioningDelegate

    public class SlidingHorizontalTransition : UIViewControllerTransitioningDelegate
        {
            private TransitionAnimator _animator;
    
            public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForPresentedController(UIViewController presented, UIViewController presenting, UIViewController source)
            {
                _animator = new TransitionAnimator();
                _animator.Presenting = true;
                return _animator;
            }
    
            public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForDismissedController(UIViewController dismissed)
            {
                _animator = new TransitionAnimator();
                return _animator;
            }
    
            private class TransitionAnimator : UIViewControllerAnimatedTransitioning
            {
                public bool Presenting;
    
                public override double TransitionDuration(IUIViewControllerContextTransitioning transitionContext)
                {
                    return 0.25f;
                }
    
            public override void AnimateTransition(IUIViewControllerContextTransitioning transitionContext)
            {
                var containerView = transitionContext.ContainerView;
                var toVC = transitionContext.GetViewControllerForKey (UITransitionContext.ToViewControllerKey);
                var fromVC = transitionContext.GetViewControllerForKey (UITransitionContext.FromViewControllerKey);
    
                if (Presenting)
                {
                    fromVC.View.UserInteractionEnabled = false;
    
                    containerView.AddSubview(fromVC.View);
                    containerView.AddSubview(toVC.View);
    
                    var endFrame = toVC.View.Frame;
                    var frame = toVC.View.Frame;
    
                    frame.X = frame.Width;
                    toVC.View.Frame = frame;
    
                    UIView.Animate(TransitionDuration(transitionContext), 0, UIViewAnimationOptions.CurveEaseIn, () =>
                        {
                            toVC.View.Frame = endFrame;
                        }, 
                        () =>
                        {
                            transitionContext.CompleteTransition(true);
                        });
                }
                else
                {
                    toVC.View.UserInteractionEnabled = true;
    
                    containerView.Add(toVC.View);
                    containerView.Add(fromVC.View);
    
                    var endFrame = fromVC.View.Frame;
                    endFrame.X = endFrame.Width;
    
                    UIView.Animate(TransitionDuration(transitionContext), 0, UIViewAnimationOptions.CurveEaseOut,async () => 
                        {
                            fromVC.View.Frame = endFrame;
                            await Task.Delay(100);
                            UIApplication.SharedApplication.KeyWindow.AddSubview(toVC.View);
    
                        }, () =>
                        {
                            transitionContext.CompleteTransition(true);
                        });
                }
            }
    

    override void WillMoveToParentViewController (UIKit.UIViewController parent)
    {
    base.WillMoveToParentViewController (parent);
    if (parent != null) {
    parent.View.BackgroundColor = UIColor.Gray;
    parent.ModalPresentationStyle = UIKit.UIModalPresentationStyle.Custom;
    parent.TransitioningDelegate = new SlidingHorizontalTransition ();

            }
    
        }
    

    :smile:

    This worked well for me. hope this helps somebody who are looking for page transitions :smile:

  • OddbjornBakkeOddbjornBakke NOMember ✭✭

    Could not get the iOS Renderer with:
    public override UIViewController PopViewController(bool animated)
    to work in Forms 2.3
    however:
    protected override Task<bool> OnPopViewAsync(Page page, bool animated)
    seems to do the trick.

    public override void PushViewController(UIViewController viewController, bool animated) works though.

  • LeonardHarrisLeonardHarris USMember
    edited July 2016

    Hi Alex we are using your custom nav animation and it is crashing throwing an exception: System.NullReferenceException: Object reference not set to an instance of an object.

    We think the issue might be in the SwitchPageAsync > OnDissapearing but there is no line number to look at when the exception is thrown.

    We can simply not get it to work having followed your 'how to' here: https://components.xamarin.com/view/customnavpage and we are using the latest version 1.3.0

    I created a very simple scenario project and below are extracts from the project (we are just trying to get it working on android first)

    App.cs below

    public App() { MainPage = new AnimationNavigationPage(new FirstPage()); }

    Firstpage.cs and the XAML contains the controls:AnimationPage

    public partial class FirstPage : AnimationPage { public FirstPage() { InitializeComponent(); Navigation.PushAsync(new NextPageAgain { PageAnimation = new FlipPageAnimation { Duration = 650, Subtype = AnimationSubtype.FromLeft } }); } }

    NextPageAgain.cs and the XAML also contains the controls:AnimationPage

    public partial class NextPageAgain : AnimationPage { public NextPageAgain() { InitializeComponent(); } }

    I am using Xamarin.Forms 2.3.1.113.pre3 and Xamarin.Android.Support 23.3.0

    If you require the entire project let me know so i can email this to you. It follows the above but is currently crashing.

  • AlexNAlexN RUMember ✭✭

    Hi Leonard!

    I see, but why you push new page in Constructor of the MainPage ?
    Please add button to your MainPage and Push new page in ButtonHandler.
    Or push new page in OnAppearing method.

«1
Sign In or Register to comment.