Skip to content

Instantly share code, notes, and snippets.

@martijn00
Last active August 9, 2019 10:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save martijn00/1c1cfd15b45057122695 to your computer and use it in GitHub Desktop.
Save martijn00/1c1cfd15b45057122695 to your computer and use it in GitHub Desktop.
Custom fragment handling in MvvmCross and Xamarin
public class CustomFragmentsPresenter : MvxFragmentsPresenter
{
public interface IMvxFragmentHostEx : IMvxFragmentHost
{
void Close(IMvxViewModel viewModel);
void ChangePresentation (MvxPresentationHint hint);
}
private IMvxNavigationSerializer _serializer;
private IMvxNavigationSerializer Serializer
{
get
{
if (_serializer != null)
return _serializer;
_serializer = Mvx.Resolve<IMvxNavigationSerializer>();
return _serializer;
}
}
public override void Show (MvxViewModelRequest request)
{
var fragmentHost = Activity as IMvxFragmentHost;
if (fragmentHost != null) {
var bundle = new Bundle ();
var serializedRequest = Serializer.Serializer.SerializeObject (request);
bundle.PutString (ViewModelRequestBundleKey, serializedRequest);
fragmentHost.Show (request, bundle);
}
else
{
var bundle = new Bundle();
var serializedRequest = Serializer.Serializer.SerializeObject(request);
bundle.PutString(ViewModelRequestBundleKey, serializedRequest);
var intentFor = new Intent (Activity.ApplicationContext, typeof(MainActivity));
intentFor.PutExtra ("request", bundle);
base.Show(intentFor);
}
}
public override void ChangePresentation (MvxPresentationHint hint)
{
if (hint != null) {
var fragmentHost = Activity as IMvxFragmentHost as IMvxFragmentHostEx;
if (fragmentHost != null) {
fragmentHost.ChangePresentation (hint);
}
}
base.ChangePresentation (hint);
}
public override void Close (IMvxViewModel viewModel)
{
var fragmentHost = Activity as IMvxFragmentHost as IMvxFragmentHostEx;
if (fragmentHost != null) {
fragmentHost.Close (viewModel);
}
base.Close (viewModel);
}
[Activity(
Label = "Menu",
Theme = "@style/AppTheme",
LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize
)]
public class MainActivity : MvxActionBarFragmentActivity, IMvxFragmentHost, CustomFragmentsPresenter.IMvxFragmentHostEx, FragmentManager.IOnBackStackChangedListener
{
public DrawerLayout drawerLayout;
private MvxActionBarDrawerToggle drawerToggle;
private FragmentManager fragmentManager;
private IMvxNavigationSerializer _serializer;
protected IMvxNavigationSerializer Serializer
{
get
{
if (_serializer != null)
return _serializer;
_serializer = Mvx.Resolve<IMvxNavigationSerializer>();
return _serializer;
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
fragmentManager = FragmentManager;
fragmentManager.AddOnBackStackChangedListener (this);
SetContentView(Resource.Layout.activity_main);
Toolbar toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
if (toolbar != null)
{
SetSupportActionBar(toolbar);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
}
drawerLayout = (DrawerLayout)FindViewById(Resource.Id.drawer);
drawerToggle = new MvxActionBarDrawerToggle(
this, /* host Activity */
drawerLayout, /* DrawerLayout object */
toolbar, /* nav drawer icon to replace 'Up' caret */
Resource.String.drawer_open, /* "open drawer" description */
Resource.String.drawer_close /* "close drawer" description */
);
drawerToggle.DrawerOpened += (o, args) =>
{
HideSoftKeyboard();
};
drawerLayout.SetDrawerListener(drawerToggle);
Bundle request = Intent.GetBundleExtra ("request");
var requestMain = new MvxViewModelRequest(typeof(MenuViewModel), null, null, null);
Show(requestMain, request);
if (request != null) {
var deserializedRequest = Serializer.Serializer.DeserializeObject<MvxViewModelRequest>(request.GetString(CustomFragmentsPresenter.ViewModelRequestBundleKey));
Show (deserializedRequest, request);
}
}
public override void OnBackPressed ()
{
//TODO: This is a fix to get the back button working. Don't know if it is a good one.
var currentFragment = fragmentManager.FindFragmentById(Resource.Id.content_frame) as MvxFragment;
if (currentFragment != null && fragmentManager.BackStackEntryCount > 1) {
fragmentManager.PopBackStackImmediate ();
return;
} else if (drawerLayout.IsDrawerOpen (GravityCompat.Start))
drawerLayout.CloseDrawers ();
else
base.OnBackPressed ();
}
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
drawerToggle.OnConfigurationChanged(newConfig);
}
protected override void OnPostCreate(Bundle savedInstanceState)
{
base.OnPostCreate(savedInstanceState);
drawerToggle.SyncState();
}
public void HideSoftKeyboard()
{
InputMethodManager manager = (InputMethodManager)GetSystemService(Context.InputMethodService);
manager.HideSoftInputFromWindow(CurrentFocus.WindowToken, 0);
}
public void ShowSoftKeyboard()
{
InputMethodManager manager = (InputMethodManager)GetSystemService(Context.InputMethodService);
manager.ShowSoftInputFromInputMethod(CurrentFocus.WindowToken, 0);
}
public bool Show (MvxViewModelRequest request, Bundle bundle)
{
if (request.ViewModelType == typeof(MenuViewModel)) {
ShowFragment (request, Resource.Id.left_drawer, bundle);
return true;
}
else if (request.ViewModelType == typeof(MiniPlayerViewModel))
{
ShowFragment(request, Resource.Id.player_frame, bundle);
return true;
}
else if (request.ViewModelType == typeof(LoginViewModel))
{
ChangePresentation(new ClearNavBackStackHint());
ShowFragment(request, Resource.Id.content_frame, bundle);
return true;
}
else {
ShowFragment(request, Resource.Id.content_frame, bundle, true);
return true;
}
}
public void ShowFragment(MvxViewModelRequest request, int contentId, Bundle bundle = null, bool addToBackStack = false)
{
MvxFragment fragment = null;
IMvxViewsContainer viewContainer = Mvx.Resolve<IMvxViewsContainer>();
Type viewType = viewContainer.GetViewType(request.ViewModelType);
Fragment currentContentFragment = FragmentManager.FindFragmentById(contentId);
if (currentContentFragment != null && currentContentFragment.GetType () == viewType && (request.ParameterValues == null || (request.ParameterValues != null && request.ParameterValues.Count == 0))) {
drawerLayout.CloseDrawers();
return;
}
SupportActionBar.Show();
drawerLayout.SetDrawerLockMode(DrawerLayout.LockModeUnlocked);
fragment = (MvxFragment)Activator.CreateInstance(viewType);
var loaderService = Mvx.Resolve<IMvxViewModelLoader>();
var viewModel = loaderService.LoadViewModel(request, null);
fragment.ViewModel = viewModel;
var contentManager = fragmentManager.BeginTransaction();
contentManager.Replace(contentId, fragment);
if(addToBackStack)
contentManager.AddToBackStack(fragment.GetType().Name);
contentManager.Commit();
drawerLayout.CloseDrawers();
}
public void OnBackStackChanged ()
{
Fragment currentPlayerFragment = fragmentManager.FindFragmentById(Resource.Id.player_frame);
Fragment currentContentFragment = FragmentManager.FindFragmentById (Resource.Id.content_frame);
if (currentPlayerFragment != null && currentContentFragment != null) {
var contentManager = fragmentManager.BeginTransaction();
if (currentContentFragment.GetType () == typeof(PlayerFragment) || currentContentFragment.GetType () == typeof(QueueFragment) || currentContentFragment.GetType () == typeof(LoginFragment))
contentManager.Hide (currentPlayerFragment);
else
contentManager.Show (currentPlayerFragment);
contentManager.Commit ();
}
}
public void ChangePresentation (MvxPresentationHint hint)
{
//TODO: Ignore this on Android for now
//if (hint is ClearNavBackStackHint)
//fragmentManager.PopBackStackImmediate(null, PopBackStackFlags.Inclusive);
}
public void Close (IMvxViewModel viewModel)
{
var currentFragment = fragmentManager.FindFragmentById (Resource.Id.content_frame) as MvxFragment;
if (currentFragment != null && currentFragment.ViewModel == viewModel) {
fragmentManager.PopBackStackImmediate ();
return;
}
}
public class ActionBarDrawerEventArgs : EventArgs
{
public View DrawerView { get; set; }
public float SlideOffset { get; set; }
public int NewState { get; set; }
}
public delegate void ActionBarDrawerChangedEventHandler(object s, ActionBarDrawerEventArgs e);
public class MvxActionBarDrawerToggle : Android.Support.V7.App.ActionBarDrawerToggle
{
public MvxActionBarDrawerToggle(Activity activity,
DrawerLayout drawerLayout,
int openDrawerContentDescRes,
int closeDrawerContentDescRes)
: base(activity,
drawerLayout,
openDrawerContentDescRes,
closeDrawerContentDescRes)
{
}
public MvxActionBarDrawerToggle(Activity activity,
DrawerLayout drawerLayout,
Toolbar toolbar,
int openDrawerContentDescRes,
int closeDrawerContentDescRes)
: base(activity,
drawerLayout,
toolbar,
openDrawerContentDescRes,
closeDrawerContentDescRes)
{
}
public event ActionBarDrawerChangedEventHandler DrawerClosed;
public event ActionBarDrawerChangedEventHandler DrawerOpened;
public event ActionBarDrawerChangedEventHandler DrawerSlide;
public event ActionBarDrawerChangedEventHandler DrawerStateChanged;
public override void OnDrawerClosed(View drawerView)
{
if (null != this.DrawerClosed)
this.DrawerClosed(this, new ActionBarDrawerEventArgs { DrawerView = drawerView });
base.OnDrawerClosed(drawerView);
}
public override void OnDrawerOpened(View drawerView)
{
if (null != this.DrawerOpened)
this.DrawerOpened(this, new ActionBarDrawerEventArgs { DrawerView = drawerView });
base.OnDrawerOpened(drawerView);
}
public override void OnDrawerSlide(View drawerView, float slideOffset)
{
if (null != this.DrawerSlide)
this.DrawerSlide(this, new ActionBarDrawerEventArgs
{
DrawerView = drawerView,
SlideOffset = slideOffset
});
base.OnDrawerSlide(drawerView, slideOffset);
}
public override void OnDrawerStateChanged(int newState)
{
if (null != this.DrawerStateChanged)
this.DrawerStateChanged(this, new ActionBarDrawerEventArgs
{
NewState = newState
});
base.OnDrawerStateChanged(newState);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment