protected virtual MvxViewPagerFragmentInfo FindFragmentInfoFromAttribute(
            MvxFragmentPresentationAttribute attribute, MvxCachingFragmentStatePagerAdapter adapter)
        {
            MvxViewPagerFragmentInfo fragmentInfo = null;

            if (attribute.Tag != null)
            {
                fragmentInfo = adapter.FragmentsInfo.FirstOrDefault(f => f.Tag == attribute.Tag);
            }

            if (fragmentInfo != null)
            {
                return(fragmentInfo);
            }

            bool IsMatch(MvxViewPagerFragmentInfo info)
            {
                if (attribute.ViewType == null)
                {
                    return(false);
                }

                var viewTypeMatches = info.FragmentType == attribute.ViewType;

                if (attribute.ViewModelType != null)
                {
                    return(viewTypeMatches && info.ViewModelType == attribute.ViewModelType);
                }

                return(viewTypeMatches);
            }

            fragmentInfo = adapter.FragmentsInfo.FirstOrDefault(IsMatch);
            return(fragmentInfo);
        }
        private void RestoreFragmentsInfoState(Bundle bundle)
        {
            if (bundle == null)
            {
                return;
            }

            var fragmentInfoParcelables = bundle.GetParcelableArray(_bundleFragmentsInfoKey);

            if (fragmentInfoParcelables == null)
            {
                return;
            }

            // First, we create a list of the ViewPager fragments that were restored by Android.
            var fragments = GetFragmentsFromBundle(bundle);

            // Now we get the FragmentInfo data for each fragment from the bundle.
            int i = 0;

            foreach (ViewPagerFragmentInfoParcelable parcelable in fragmentInfoParcelables)
            {
                MvxViewPagerFragmentInfo fragInfo = null;

                if (i < fragments.Count)
                {
                    var f = fragments[i];
                    if (f is IMvxFragmentView fragment && fragment.ViewModel != null)
                    {
                        // The fragment was already restored by Android with its old ViewModel (cached by MvvmCross).
                        // Add the ViewModel to the FragmentInfo object so the adapter won't instantiate a new one.
                        var viewModelInstanceRequest = new MvxViewModelInstanceRequest(fragment.ViewModel);
                        fragInfo = new MvxViewPagerFragmentInfo(parcelable.Title, parcelable.Tag, parcelable.FragmentType, viewModelInstanceRequest);
                    }
                }

                if (fragInfo == null)
                {
                    // Either the fragment doesn't exist or it doesn't have a ViewModel.
                    // Fall back to a FragmentInfo with the ViewModelType. The adapter will create a ViewModel in GetItem where we will add it to the FragmentInfo.
                    var viewModelRequest = new MvxViewModelRequest(parcelable.ViewModelType);
                    fragInfo = new MvxViewPagerFragmentInfo(parcelable.Title, parcelable.Tag, parcelable.FragmentType, viewModelRequest);
                }

                FragmentsInfo.Add(fragInfo);
                i++;
            }

            NotifyDataSetChanged();
        }
        public override Fragment GetItem(int position, Fragment.SavedState fragmentSavedState = null)
        {
            var fragment = base.GetItem(position, fragmentSavedState);

            // If the MvxViewPagerFragmentInfo for this position doesn't have the ViewModel, overwrite it with a new MvxViewPagerFragmentInfo that has the ViewModel we just created.
            // Not doing this means the ViewModel gets recreated every time the Fragment gets recreated!
            if (FragmentsInfo != null && FragmentsInfo.Count > position && fragment is IMvxFragmentView mvxFragment && mvxFragment.ViewModel != null)
            {
                var oldFragInfo = FragmentsInfo[position];

                if (oldFragInfo != null && oldFragInfo.ViewModel == null)
                {
                    var newFragInfo = new MvxViewPagerFragmentInfo(oldFragInfo.Title, oldFragInfo.Tag, oldFragInfo.FragmentType, mvxFragment.ViewModel);
                    FragmentsInfo[position] = newFragInfo;
                }
            }

            return(fragment);
        }
Example #4
0
        protected virtual Task <bool> ShowViewPagerFragment(
            Type view,
            MvxViewPagerFragmentPresentationAttribute attribute,
            MvxViewModelRequest request)
        {
            ValidateArguments(view, attribute, request);

            // if the attribute doesn't supply any host, assume current activity!
            if (attribute.FragmentHostViewType == null && attribute.ActivityHostViewModelType == null)
            {
                attribute.ActivityHostViewModelType = GetCurrentActivityViewModelType();
            }

            ViewPager?      viewPager       = null;
            FragmentManager?fragmentManager = null;

            // check for a ViewPager inside a Fragment
            if (attribute.FragmentHostViewType != null)
            {
                var fragment = GetFragmentByViewType(attribute.FragmentHostViewType);
                if (fragment == null)
                {
                    throw new MvxException("Fragment not found", attribute.FragmentHostViewType.Name);
                }

                if (fragment.View == null)
                {
                    throw new MvxException("Fragment.View is null. Please consider calling Navigate later in your code",
                                           attribute !.FragmentHostViewType.Name);
                }

                viewPager       = fragment.View.FindViewById <ViewPager>(attribute.ViewPagerResourceId);
                fragmentManager = fragment.ChildFragmentManager;
            }

            // check for a ViewPager inside an Activity
            if (attribute.ActivityHostViewModelType != null)
            {
                var currentActivityViewModelType = GetCurrentActivityViewModelType();

                // if the host Activity is not the top-most Activity, then show it before proceeding, and return false for now
                if (attribute.ActivityHostViewModelType != currentActivityViewModelType)
                {
                    PendingRequest = request;
                    ShowHostActivity(attribute);
                    return(Task.FromResult(false));
                }

                if (CurrentActivity.IsActivityAlive())
                {
                    viewPager = CurrentActivity !.FindViewById <ViewPager>(attribute.ViewPagerResourceId);
                }
                fragmentManager = CurrentFragmentManager;
            }

            // no more cases to check. Just throw if ViewPager wasn't found
            if (viewPager == null)
            {
                throw new MvxException("ViewPager not found");
            }

            var tag          = attribute.Tag ?? attribute.ViewType.FragmentJavaName();
            var fragmentInfo = new MvxViewPagerFragmentInfo(attribute.Title, tag, attribute.ViewType, request);

            if (viewPager.Adapter is MvxCachingFragmentStatePagerAdapter adapter)
            {
                adapter.FragmentsInfo.Add(fragmentInfo);
                adapter.NotifyDataSetChanged();
            }
            else
            {
                viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(
                    CurrentActivity,
                    fragmentManager,
                    new List <MvxViewPagerFragmentInfo>
                {
                    fragmentInfo
                }
                    );
            }

            return(Task.FromResult(true));
        }