Skip to content

Instantly share code, notes, and snippets.

@ivmirx
Last active June 25, 2022 14:09
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivmirx/24e3ad1e4f8d965d9d16739671949ae5 to your computer and use it in GitHub Desktop.
Save ivmirx/24e3ad1e4f8d965d9d16739671949ae5 to your computer and use it in GitHub Desktop.
Using the new Android's BottomNavigationView with MvvmCross 6
<!-- Resources/layout/bottom_navigation.axml -->
<!-- "android:titleCondensed" is used as tab ID -->
<?xml version="1.0" encoding="UTF-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/tab_first"
android:enabled="true"
android:icon="@drawable/tab_first"
android:title="First"
android:titleCondensed="tab_first"
app:showAsAction="always" />
<item
android:id="@+id/tab_second"
android:enabled="true"
android:icon="@drawable/tab_second"
android:title="Second"
android:titleCondensed="tab_second"
app:showAsAction="always" />
<item
android:id="@+id/tab_third"
android:enabled="true"
android:icon="@drawable/tab_third"
android:title="Third"
android:titleCondensed="tab_third"
app:showAsAction="always" />
</menu>
// a custom binding for Droid to get "app:MvxBind" in root_view working
using System;
using Android.Support.Design.Widget;
using MvvmCross.Binding;
using MvvmCross.Commands;
using MvvmCross.Platforms.Android.Binding.Target;
namespace YourApp.Droid.Bindings
{
public class MvxBottomNavigationItemChangedBinding : MvxAndroidTargetBinding
{
readonly BottomNavigationView _bottomNav;
IMvxCommand _command;
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
public override Type TargetType => typeof(MvxCommand);
public MvxBottomNavigationItemChangedBinding(BottomNavigationView bottomNav) : base(bottomNav)
{
_bottomNav = bottomNav;
_bottomNav.NavigationItemSelected += OnNavigationItemSelected;
}
public override void SetValue(object value)
{
_command = (IMvxCommand)value;
}
protected override void SetValueImpl(object target, object value)
{
}
void OnNavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
{
if (_command != null)
_command.Execute(e.Item.TitleCondensedFormatted.ToString());
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
_bottomNav.NavigationItemSelected -= OnNavigationItemSelected;
base.Dispose(isDisposing);
}
}
}
<!-- Resources/layout/root_view.axml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="25px"
android:minHeight="25px">
<FrameLayout
android:id="@+id/tabs_container_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_navigation"
android:background="@android:color/holo_purple" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
app:itemIconTint="@color/bottom_navigation_colors"
app:itemTextColor="@color/bottom_navigation_colors"
app:menu="@menu/bottom_navigation"
app:MvxBind="BottomNavigationSelectedBindingKey BottomNavigationItemSelectedCommand" />
</RelativeLayout>
// the root view of your Droid hierarchy, it uses fragments for tabs
using Android.App;
using Android.OS;
using Android.Support.Design.Widget;
using MvvmCross.Droid.Support.V7.AppCompat; // don't forget to install this package from NuGet
using MvvmCross.Platforms.Android.Presenters.Attributes;
using YourApp.Core.ViewModels; // the namespace where your RootViewModel is
namespace YourApp.Droid
{
[Activity(Label = "YourAppName")]
[MvxActivityPresentation]
public class RootView : MvxAppCompatActivity<RootViewModel>
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.root_view);
var bottomNavigation = FindViewById<BottomNavigationView>(Resource.Id.bottom_navigation);
ViewModel.BottomNavigationItemSelectedCommand.Execute(ViewModel.Tabs[0].TabId);
}
}
}
// the root view model in your Core project
using MvvmCross;
using MvvmCross.Commands;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
using System.Collections.Generic;
namespace YourApp.Core.ViewModels
{
public class RootViewModel : MvxViewModel
{
public IMvxCommand<string> BottomNavigationItemSelectedCommand { get; private set; }
List<TabViewModel> _tabs;
public List<TabViewModel> Tabs
{
get => _tabs;
set => SetProperty(ref _tabs, value);
}
readonly IMvxNavigationService _navigationService;
public RootViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
BottomNavigationItemSelectedCommand = new MvxCommand<string>(BottomNavigationItemSelected);
var tabs = new List<TabViewModel>
{
Mvx.IoCConstruct<FirstViewModel>(),
Mvx.IoCConstruct<SecondViewModel>(),
Mvx.IoCConstruct<ThirdViewModel>(),
};
Tabs = tabs;
}
// Android-only, not used on iOS
void BottomNavigationItemSelected(string tabId)
{
foreach (var item in Tabs)
{
if (tabId == item.TabId)
{
_navigationService.Navigate(item);
break;
}
}
}
}
}
// you need a custom MvxAndroidSetup to register the custom binding
using Android.Support.Design.Widget;
using YourApp.Core;
using YourApp.Droid.Bindings;
using MvvmCross.Binding.Bindings.Target.Construction;
using MvvmCross.Droid.Support.V7.AppCompat;
using MvvmCross.Platforms.Android.Core;
namespace YourApp.Droid
{
public class Setup : MvxAndroidSetup<App>
{
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
MvxAppCompatSetupHelper.FillTargetFactories(registry);
base.FillTargetFactories(registry);
registry.RegisterCustomBindingFactory<BottomNavigationView>("BottomNavigationSelectedBindingKey",
view => new MvxBottomNavigationItemChangedBinding(view));
}
}
}
// subclass this with your tab view models and set the IDs equal to "android:titleCondensed" in bottom_navigation.axml
using MvvmCross;
using MvvmCross.ViewModels;
namespace YourApp.Core.ViewModels
{
public class TabViewModel : MvxViewModel
{
public string TabName { get; protected set; }
public string TabId { get; protected set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment