Last active
December 23, 2015 19:46
-
-
Save dbeattie71/bbf27cf2612f34fb8031 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using Android.OS; | |
| using Android.Runtime; | |
| using Android.Support.V4.App; | |
| using Android.Support.V4.View; | |
| using Android.Views; | |
| using Cirrious.CrossCore; | |
| using Java.Lang; | |
| using Object = Java.Lang.Object; | |
| namespace EnjinMobile.Common | |
| { | |
| //http://speakman.net.nz/blog/2014/02/20/a-bug-in-and-a-fix-for-the-way-fragmentstatepageradapter-handles-fragment-restoration/ | |
| //https://github.com/adamsp/FragmentStatePagerIssueExample/blob/master/app/src/main/java/com/example/fragmentstatepagerissueexample/app/FixedFragmentStatePagerAdapter.java | |
| public abstract class FixedFragmentStatePagerAdapter : PagerAdapter | |
| { | |
| private Fragment _currentPrimaryItem; | |
| private FragmentTransaction _curTransaction; | |
| private readonly FragmentManager _fragmentManager; | |
| private readonly List<Fragment> _fragments = new List<Fragment>(); | |
| private List<string> _savedFragmentTags = new List<string>(); | |
| private readonly List<Fragment.SavedState> _savedState = new List<Fragment.SavedState>(); | |
| protected FixedFragmentStatePagerAdapter(IntPtr javaReference, JniHandleOwnership transfer) | |
| : base(javaReference, transfer) | |
| { | |
| } | |
| protected FixedFragmentStatePagerAdapter(FragmentManager fragmentManager) | |
| { | |
| _fragmentManager = fragmentManager; | |
| } | |
| public abstract Fragment GetItem(int position, Fragment.SavedState fragmentSavedState = null); | |
| public override void DestroyItem(ViewGroup container, int position, Object objectValue) | |
| { | |
| var fragment = (Fragment) objectValue; | |
| if (_curTransaction == null) | |
| _curTransaction = _fragmentManager.BeginTransaction(); | |
| #if DEBUG | |
| Mvx.Trace("Removing item #" + position + ": f=" + objectValue + " v=" + ((Fragment) objectValue).View + | |
| " t=" + fragment.Tag); | |
| #endif | |
| while (_savedState.Count <= position) | |
| { | |
| _savedState.Add(null); | |
| _savedFragmentTags.Add(null); | |
| } | |
| _savedState[position] = _fragmentManager.SaveFragmentInstanceState(fragment); | |
| _savedFragmentTags[position] = fragment.Tag; | |
| _fragments[position] = null; | |
| _curTransaction.Remove(fragment); | |
| } | |
| public override void FinishUpdate(ViewGroup container) | |
| { | |
| if (_curTransaction == null) | |
| return; | |
| _curTransaction.CommitAllowingStateLoss(); | |
| _curTransaction = null; | |
| _fragmentManager.ExecutePendingTransactions(); | |
| } | |
| public override Object InstantiateItem(ViewGroup container, int position) | |
| { | |
| // If we already have this item instantiated, there is nothing | |
| // to do. This can happen when we are restoring the entire pager | |
| // from its saved state, where the fragment manager has already | |
| // taken care of restoring the fragments we previously had instantiated. | |
| if (_fragments.Count > position) | |
| { | |
| var existingFragment = _fragments.ElementAtOrDefault(position); | |
| if (existingFragment != null) | |
| return existingFragment; | |
| } | |
| if (_curTransaction == null) | |
| _curTransaction = _fragmentManager.BeginTransaction(); | |
| var fragmentTag = GetTag(position); | |
| Fragment.SavedState fss = null; | |
| if (_savedState.Count > position) | |
| { | |
| var savedTag = _savedFragmentTags.ElementAtOrDefault(position); | |
| if (string.Equals(fragmentTag, savedTag)) | |
| fss = _savedState.ElementAtOrDefault(position); | |
| } | |
| var fragment = GetItem(position, fss); | |
| if (fss != null) | |
| fragment.SetInitialSavedState(fss); | |
| #if DEBUG | |
| Mvx.Trace("Adding item #" + position + ": f=" + fragment + " t=" + fragmentTag); | |
| #endif | |
| while (_fragments.Count <= position) | |
| _fragments.Add(null); | |
| fragment.SetMenuVisibility(false); | |
| fragment.UserVisibleHint = false; | |
| _fragments[position] = fragment; | |
| _curTransaction.Add(container.Id, fragment, fragmentTag); | |
| return fragment; | |
| } | |
| public override bool IsViewFromObject(View view, Object objectValue) | |
| { | |
| return ((Fragment) objectValue).View == view; | |
| } | |
| public override void RestoreState(IParcelable state, ClassLoader loader) | |
| { | |
| if (state == null) | |
| return; | |
| var bundle = (Bundle) state; | |
| bundle.SetClassLoader(loader); | |
| var fss = bundle.GetParcelableArray("states"); | |
| _savedState.Clear(); | |
| _fragments.Clear(); | |
| var tags = bundle.GetStringArrayList("tags"); | |
| if (tags != null) | |
| _savedFragmentTags = tags.ToList(); | |
| else | |
| _savedFragmentTags.Clear(); | |
| if (fss != null) | |
| { | |
| for (var i = 0; i < fss.Length; i++) | |
| { | |
| var parcelable = fss.ElementAt(i); | |
| var savedState = parcelable.JavaCast<Fragment.SavedState>(); | |
| _savedState.Add(savedState); | |
| } | |
| } | |
| var keys = bundle.KeySet(); | |
| foreach (var key in keys) | |
| { | |
| if (!key.StartsWith("f")) | |
| continue; | |
| var index = Integer.ParseInt(key.Substring(1)); | |
| var f = _fragmentManager.GetFragment(bundle, key); | |
| if (f != null) | |
| { | |
| while (_fragments.Count() <= index) | |
| _fragments.Add(null); | |
| f.SetMenuVisibility(false); | |
| _fragments[index] = f; | |
| } | |
| } | |
| } | |
| public override IParcelable SaveState() | |
| { | |
| Bundle state = null; | |
| if (_savedState.Any()) | |
| { | |
| state = new Bundle(); | |
| var fss = new IParcelable[_savedState.Count]; | |
| for (var i = 0; i < _savedState.Count; i++) | |
| fss[i] = _savedState.ElementAt(i); | |
| state.PutParcelableArray("states", fss); | |
| state.PutStringArrayList("tags", _savedFragmentTags); | |
| } | |
| for (var i = 0; i < _fragments.Count; i++) | |
| { | |
| var f = _fragments.ElementAtOrDefault(i); | |
| if (f == null) | |
| continue; | |
| if (state == null) | |
| state = new Bundle(); | |
| var key = "f" + i; | |
| _fragmentManager.PutFragment(state, key, f); | |
| } | |
| return state; | |
| } | |
| public override void SetPrimaryItem(ViewGroup container, int position, Object objectValue) | |
| { | |
| var fragment = (Fragment) objectValue; | |
| if (fragment == _currentPrimaryItem) | |
| return; | |
| if (_currentPrimaryItem != null) | |
| { | |
| _currentPrimaryItem.SetMenuVisibility(false); | |
| _currentPrimaryItem.UserVisibleHint = false; | |
| } | |
| if (fragment != null) | |
| { | |
| fragment.SetMenuVisibility(true); | |
| fragment.UserVisibleHint = true; | |
| } | |
| _currentPrimaryItem = fragment; | |
| } | |
| public override void StartUpdate(View container) | |
| { | |
| } | |
| protected virtual string GetTag(int position) | |
| { | |
| return null; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using Android.Content; | |
| using Android.Runtime; | |
| using Android.Support.V4.App; | |
| using Cirrious.CrossCore; | |
| using Cirrious.MvvmCross.Platform; | |
| using Cirrious.MvvmCross.ViewModels; | |
| using EnjinMobile.Common; | |
| using Java.Lang; | |
| using MvvmCross.Droid.Support.V7.Fragging; | |
| using MvvmCross.Droid.Support.V7.Fragging.Fragments; | |
| using String = Java.Lang.String; | |
| namespace EnjinMobile.Droid.Framework | |
| { | |
| public class MvxFixedFragmentStatePagerAdapter | |
| : FixedFragmentStatePagerAdapter | |
| { | |
| private readonly Context _context; | |
| protected MvxFixedFragmentStatePagerAdapter(IntPtr javaReference, JniHandleOwnership transfer) | |
| : base(javaReference, transfer) | |
| { | |
| } | |
| public MvxFixedFragmentStatePagerAdapter(Context context, FragmentManager fragmentManager, | |
| IEnumerable<FragmentInfo> fragments) | |
| : base(fragmentManager) | |
| { | |
| _context = context; | |
| Fragments = fragments; | |
| } | |
| public override int Count => Fragments.Count(); | |
| public IEnumerable<FragmentInfo> Fragments { get; } | |
| protected static string FragmentJavaName(Type fragmentType) | |
| { | |
| var namespaceText = fragmentType.Namespace ?? ""; | |
| if (namespaceText.Length > 0) | |
| namespaceText = namespaceText.ToLowerInvariant() + "."; | |
| return namespaceText + fragmentType.Name; | |
| } | |
| public override Fragment GetItem(int position, Fragment.SavedState fragmentSavedState = null) | |
| { | |
| var fragInfo = Fragments.ElementAt(position); | |
| var fragment = Fragment.Instantiate(_context, FragmentJavaName(fragInfo.FragmentType)); | |
| var mvxFragment = fragment as MvxFragment; | |
| if (mvxFragment == null) | |
| return fragment; | |
| if (mvxFragment.GetType().IsCacheableFragmentAttribute() && fragmentSavedState != null) | |
| return fragment; | |
| var viewModel = CreateViewModel(position); | |
| mvxFragment.ViewModel = viewModel; | |
| return fragment; | |
| } | |
| public override ICharSequence GetPageTitleFormatted(int position) | |
| { | |
| return new String(Fragments.ElementAt(position).Title); | |
| } | |
| protected override string GetTag(int position) | |
| { | |
| return Fragments.ElementAt(position).Tag; | |
| } | |
| private IMvxViewModel CreateViewModel(int position) | |
| { | |
| var fragInfo = Fragments.ElementAt(position); | |
| MvxBundle mvxBundle = null; | |
| if (fragInfo.ParameterValuesObject != null) | |
| mvxBundle = new MvxBundle(fragInfo.ParameterValuesObject.ToSimplePropertyDictionary()); | |
| var request = new MvxViewModelRequest(fragInfo.ViewModelType, mvxBundle, null, null); | |
| return Mvx.Resolve<IMvxViewModelLoader>().LoadViewModel(request, null); | |
| } | |
| //Do call restore state | |
| //public override void RestoreState(IParcelable state, ClassLoader loader) | |
| //{ | |
| // //Don't call restore to prevent crash on rotation | |
| // //base.RestoreState (state, loader); | |
| //} | |
| public class FragmentInfo | |
| { | |
| public FragmentInfo(string title, Type fragmentType, Type viewModelType, object parameterValuesObject = null) | |
| : this(title, null, fragmentType, viewModelType, parameterValuesObject) | |
| { | |
| } | |
| public FragmentInfo(string title, string tag, Type fragmentType, Type viewModelType, | |
| object parameterValuesObject = null) | |
| { | |
| Title = title; | |
| Tag = tag ?? title; | |
| FragmentType = fragmentType; | |
| ViewModelType = viewModelType; | |
| ParameterValuesObject = parameterValuesObject; | |
| } | |
| public Type FragmentType { get; } | |
| public object ParameterValuesObject { get; } | |
| public string Tag { get; } | |
| public string Title { get; } | |
| public Type ViewModelType { get; } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment