Search code examples
android-fragmentsxamarinxamarin.androidmvvmcrossfragment-transitions

Mvvmcross Android Fragment (ShowViewModel) Custom Animation effect (swipe)


I have a problem with override Custom Animation on my Fragment. I have on my Home view three buttons (First, Second and Third) and when I'm inside this views I want swipe between those view and I need swipe animation effect from left to right and from right to left etc..

For Example my SecondFragments looks like this:

[MvxFragment(typeof(MainViewModel), Resource.Id.content_frame, true)]
    public class SecondFragment : BaseFragment<SecondViewModel>, View.IOnTouchListener
    {
        private Easter _easter;
        protected override int FragmentId => Resource.Layout.fragment_second;

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            var view = base.OnCreateView(inflater, container, savedInstanceState);

            _easter = new Easter(new KonamiCode());

            var easyEgg = new CustomEgg("Easy")
                .WatchForSequence(Command.SwipeLeft(), Command.SwipeRight());

            _easter = new Easter(easyEgg);=
            _easter.CommandDetected += cmd => DoSwipe(cmd.Value);

            var coreLayout = view.FindViewById<LinearLayout>(Resource.Id.coreLayout);
            coreLayout?.SetOnTouchListener(this);

            return view;
        }

        private void DoSwipe(string swipeText)
        {
            if (swipeText.Equals("LEFT"))
            {
                Activity.OverridePendingTransition(Resource.Animator.slide_to_right, Resource.Animator.slide_from_left);
            }

            if (swipeText.Equals("RIGHT"))
            {
                Activity.OverridePendingTransition(Resource.Animator.slide_to_left, Resource.Animator.slide_from_right);
            }

            ViewModel.SwipeView(swipeText);
        }

        public bool OnTouch(View v, MotionEvent e)
        {
            _easter.OnTouchEvent(e);
            return true;
        }
    }

Method ViewModel.SwipeView looks like:

public override void SwipeView(string swipeText)
        {
            if (swipeText.Equals("RIGHT"))
            {
                Close(this);
                UserDialogs.Instance.Toast("RIGHT SWIPE!");
                ShowViewModel<FirstViewModel>();
            }

            if (swipeText.Equals("LEFT"))
            {
                Close(this);
                UserDialogs.Instance.Toast("LEFT SWIPE!");
                ShowViewModel<ThirdViewModel>();
            }
        }

I tried Activity.OverridePendingTransition for this but it doesnt work. I tried something with TransactionManager but still doesnt work. I need just override animations only for these three view no for whole app.

For example my test project is HERE on github.


Solution

  • I tried Activity.OverridePendingTransition for this but it doesnt work.

    OverridePendingTransition allows you to specify a custom animation when starting an activity from outside the Context of the current top Activity. That means OverridePendingTransition method only be called immediately after one of the flavors of startActivity(Intent) or finish() to specify an explicit transition animation to perform next. So when you swipe between those Fragment, it has no effect.

    Difference between Animator folder and Anim fodler.

    An animation resource can define one of two types of animations: Property Animation and View Animation.

    1. Property Animation

      File Location:

      Resource/animator/filename.xml
      

      SYNTAX:

      The file must have a single root element: either <set>, <objectAnimator>, or <valueAnimator>. You can group animation elements together inside the <set> element, including other <set> elements.

    2. View Animation

      File Location:

      Resource/anim/filename.xml
      

      SYNTAX:

      The file must have a single root element: either an <alpha>, <scale>, <translate>, <rotate>, or <set> element that holds a group (or groups) of other animation elements (even nested <set> elements).

    Since your animation use translate, I suggest you put these xml file in Resource/anim folder.

    I need just override animations only for these three view no for whole app.

    Since your base Activity is MvxCachingFragmentCompatActivityas, you can override OnBeforeFragmentChanging method to set a custom transition animation.

    public override void OnBeforeFragmentChanging(MvvmCross.Droid.Shared.Caching.IMvxCachedFragmentInfo fragmentInfo, Android.Support.V4.App.FragmentTransaction transaction)
    {
        //Replace this animation with your own animation.
        transaction.SetCustomAnimations(
            // Your entrance animation xml reference
            Resource.Animation.abc_fade_in,
            // Your exit animation xml reference
            Resource.Animation.abc_fade_out,
            Resource.Animation.abc_fade_in,
            Resource.Animation.abc_fade_out);
    
            base.OnBeforeFragmentChanging(fragmentInfo, transaction);
    }
    

    SetCustomAnimations set specific animation resources to run for the fragments that are entering and exiting in this transaction. The popEnter and popExit animations will be played for enter/exit operations specifically when popping the back stack.

    FragmentTransaction setCustomAnimations (int enter, 
                int exit, 
                int popEnter, 
                int popExit) 
    

    EDIT :

    Custom animation for every swipe between Fragment, for every Fragment, you could custom animation like this :

    [MvxFragment(typeof(MainViewModel), Resource.Id.content_frame, true)]
    public class SecondFragment : BaseFragment<SecondViewModel>, View.IOnTouchListener
    { 
        private void DoSwipe(string swipeText)
        {
            if (swipeText.Equals("LEFT"))
            {
                FragmentManager.BeginTransaction()
                    .SetCustomAnimations(Resource.Animation.slide_from_left, Resource.Animation.slide_from_right)
                    .Replace(Resource.Id.content_frame,ThirdFragment.NewInstance(null))
                    .Commit();
            }
            if (swipeText.Equals("RIGHT"))
            {
                ...
            }
    
            ViewModel.SwipeView(swipeText);
        }
    }