Is there an example of Android Shared Element navigation from Xamarin Mvvmcross?

I am trying to get this animation / transition working in my Xamarin Android app with Mvx.

I have a recyclerview with maps. When you click on the card, I now call:

private void TimeLineAdapterOnItemClick(object sender, int position)
{
    TimeLineAdapter ta = (TimeLineAdapter) sender;
    var item = ta.Items[position];

    int photoNum = position + 1;
    Toast.MakeText(Activity, "This is photo number " + photoNum, ToastLength.Short).Show();

    ViewModel.ShowDetails(item.Id);
}

      

I'm trying to figure out how to translate this java navigation to Xamarin using Mvvmcross:

ActivityOptionsCompat options = 
   ActivityOptionsCompat.MakeSceneTransitionAnimation(this, imageView, getString(R.string.activity_image_trans));

startActivity(intent, options.toBundle());

      

I know that in Mvx you can use custom presenters, but how can I get, for example, an ImageView of a typed Map in a RecyclerView that I would like to "convert" to a new ImageView on a new activity?

Thank!

...

+4


source to share


1 answer


  Is there a Xamarin Mvvmcross Android generic navigation? Example?

I do not believe in that.

I know you can use custom presenters in Mvx, but how do I get, for example, an image in a rotated map in a RecyclerView that I would like to "convert" to a new ImageView on a new activity?

The easiest way I can think of to share the controls that you want to move is to use presentation and presentation package tags when in use ShowViewModel

.

I would suggest making some changes to your adapter click handler to include the view of the selected ViewHolder

(see the GitHub repo , for example with EventArgs). This way you can interact with ImageView

and set a tag that you can use later to identify it.

private void TimeLineAdapterOnItemClick(object sender, View e)
{
    var imageView = e.FindViewById<ImageView>(Resource.Id.imageView);
    imageView.Tag = "anim_image";

    ViewModel.ShowDetails(imageView.Tag.ToString());
}

      

Then in your ViewModel send this tag through the presentation.

public void ShowDetails(string animationTag)
{
    var presentationBundle = new MvxBundle(new Dictionary<string, string>
    {
        ["Animate_Tag"] = animationTag
    });

    ShowViewModel<DetailsViewModel>(presentationBundle: presentationBundle);
}

      

Then create your own presenter to pick up presentationBundle

and handle creating a new transition action. A custom presenter that uses a tag to find the element you want to move and include ActivityOptionsCompat

at the start of a new activity. This example uses MvxFragmentsPresenter

, but if you don't use snippets and use MvxAndroidViewPresenter

, the solution will be almost identical (instead of Override Show and no constructor is required).



public class SharedElementFragmentsPresenter : MvxFragmentsPresenter
{
    public SharedElementFragmentsPresenter(IEnumerable<Assembly> AndroidViewAssemblies)
        : base(AndroidViewAssemblies)
    {
    }

    protected override void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null)
    {
        if (InterceptPresenter(request))
            return;

        Show(request, fragmentRequest);
    }

    private bool InterceptPresenter(MvxViewModelRequest request)
    {
        if ((request.PresentationValues?.ContainsKey("Animate_Tag") ?? false)
            && request.PresentationValues.TryGetValue("Animate_Tag", out var controlTag))
        {
            var intent = CreateIntentForRequest(request);

            var control = Activity.FindViewById(Android.Resource.Id.Content).FindViewWithTag(controlTag);
            control.Tag = null;

            var transitionName = control.GetTransitionNameSupport();
            if (string.IsNullOrEmpty(transitionName))
            {
                Mvx.Warning($"A {nameof(transitionName)} is required in order to animate a control.");
                return false;
            }

            var activityOptions = ActivityOptionsCompat.MakeSceneTransitionAnimation(Activity, control, transitionName);

            Activity.StartActivity(intent, activityOptions.ToBundle());
            return true;
        }

        return false;
    }
}

      

GetTransitionNameSupport

is an extension method that simply checks the platform API upon receipt TransitionName

.

public static string GetTransitionNameSupport(this ImageView imageView)
{
    if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
        return imageView.TransitionName;

    return string.Empty;
}

      

The last step is registering your own speaker with you Setup.cs

protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
    var mvxPresenter = new SharedElementFragmentsPresenter(AndroidViewAssemblies);
    Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxPresenter);
    return mvxPresenter;
}

      


You can check out the repo on GitHub that demonstrates this example. The solution is designed so that the presenter does not have to worry about the type of control that is being wrapped. The control only requires a tag used to identify it. The example in the repository also allows you to specify multiple controls that you want to translate (I didn't want to include a more complex task in the above example).

Shared Element Demo

+9


source







All Articles