【xamarin + MvvmCross 從零開始】8、Android Fragment 的使用

前言

上一節咱們講解了在Android平臺如何經過MvvmCross實現啓動界面,以及如何處理啓動時的白屏問題。html

這一節咱們講解一下如何在Android平臺使用Fragment。java

Fragment 應用

什麼是Fragment

Fragment是Android開發經常使用的一種組件。經過Fragment的使用能夠下降內存的使用,增長App的流暢度。已經有不少大神講解過Fragment的內容了,請看這裏android

MvvmCross中與Fragment相關的對象

在MvvmCross中,已經實現了不少與Fragment相關的對象,極大的方便咱們的使用。git

首先咱們須要經過nuget 添加MvvmCross對Fragment的支持庫 MvvmCross.Droid.FullFragging。如今咱們來看一下MvvmCross爲咱們實現了哪些相關的對象。github

image

這裏咱們會使用如下幾個MvvmCross定義的幾個對象:微信

  • MvxFragment: Fragment對象的基類,全部基於MvvvmCross實現的Fragment都須要今後對象繼承。
namespace MvvmCross.Droid.FullFragging.Fragments
{
    [Register("mvvmcross.droid.fullfragging.fragments.MvxFragment")]
    public class MvxFragment : MvxEventSourceFragment, IMvxFragmentView, IMvxBindingContextOwner, IMvxView, IMvxDataConsumer
    {
        protected MvxFragment();
        protected MvxFragment(IntPtr javaReference, JniHandleOwnership transfer);

        public IMvxBindingContext BindingContext { get; set; }
        public object DataContext { get; set; }
        public string UniqueImmutableCacheTag { get; }
        public virtual IMvxViewModel ViewModel { get; set; }

        public static MvxFragment NewInstance(Bundle bundle);
        public virtual void OnViewModelSet();
    }
}
查看代碼
  • MvxFragmentAttribute,Fragment特性標籤,標識了當前Fragment的嵌入的宿主以及顯示時後些參數
namespace MvvmCross.Droid.Shared.Attributes
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public class MvxFragmentAttribute : Attribute
    {
        public MvxFragmentAttribute(Type parentActivityViewModelType, int fragmentContentId, bool addToBackStack = false);

        public bool AddToBackStack { get; set; }
        public int FragmentContentId { get; }
        public bool IsCacheableFragment { get; set; }
        public Type ParentActivityViewModelType { get; }
        public Type ViewModelType { get; set; }
    }
}
查看代碼
  • MvxCachingFragmentActivity:Fragment的宿主窗口
namespace MvvmCross.Droid.FullFragging.Caching
{
    [Register("mvvmcross.droid.fullfragging.caching.MvxCachingFragmentActivity")]
    public class MvxCachingFragmentActivity : MvxActivity, IFragmentCacheableActivity, IMvxFragmentHost
    {
        public const string ViewModelRequestBundleKey = "__mvxViewModelRequest";

        protected MvxCachingFragmentActivity();
        protected MvxCachingFragmentActivity(IntPtr javaReference, JniHandleOwnership transfer);

        public IFragmentCacheConfiguration FragmentCacheConfiguration { get; }

        public virtual IFragmentCacheConfiguration BuildFragmentCacheConfiguration();
        public virtual bool Close(IMvxViewModel viewModel);
        public override void OnBackPressed();
        public virtual void OnBeforeFragmentChanging(IMvxCachedFragmentInfo fragmentInfo, FragmentTransaction transaction);
        public virtual void OnFragmentChanged(IMvxCachedFragmentInfo fragmentInfo);
        public virtual void OnFragmentChanging(IMvxCachedFragmentInfo fragmentInfo, FragmentTransaction transaction);
        public virtual void OnFragmentCreated(IMvxCachedFragmentInfo fragmentInfo, FragmentTransaction transaction);
        public virtual void OnFragmentPopped(IList<IMvxCachedFragmentInfo> currentFragmentsInfo);
        public virtual bool Show(MvxViewModelRequest request, Bundle bundle, Type fragmentType, MvxFragmentAttribute fragmentAttribute);
        protected virtual void CloseFragment(string tag, int contentId);
        protected virtual string FragmentJavaName(Type fragmentType);
        protected virtual IEnumerable<Fragment> GetCurrentCacheableFragments();
        protected virtual List<IMvxCachedFragmentInfo> GetCurrentCacheableFragmentsInfo();
        protected IMvxCachedFragmentInfo GetFragmentInfoByTag(string tag);
        protected virtual string GetFragmentTag(MvxViewModelRequest request, Bundle bundle, Type fragmentType);
        protected virtual IMvxCachedFragmentInfo GetLastFragmentInfo();
        protected virtual string GetTagFromFragment(Fragment fragment);
        protected override void OnCreate(Bundle bundle);
        protected override void OnPostCreate(Bundle savedInstanceState);
        protected override void OnSaveInstanceState(Bundle outState);
        protected virtual void ReplaceFragment(FragmentTransaction ft, IMvxCachedFragmentInfo fragInfo);
        protected virtual FragmentReplaceMode ShouldReplaceCurrentFragment(IMvxCachedFragmentInfo newFragment, IMvxCachedFragmentInfo currentFragment, Bundle replacementBundle);
        protected virtual void ShowFragment(string tag, int contentId, Bundle bundle, bool forceAddToBackStack = false, bool forceReplaceFragment = false);

        protected enum FragmentReplaceMode
        {
            NoReplace = 0,
            ReplaceFragment = 1,
            ReplaceFragmentAndViewModel = 2
        }
    }
}
查看代碼
  • MvxFragmentsPresenter,實對Fragment對象的顯示,內部對象,MvvmCross框架將自動調用
namespace MvvmCross.Droid.Shared.Presenter
{
    public class MvxFragmentsPresenter : MvxAndroidViewPresenter
    {
        public const string ViewModelRequestBundleKey = "__mvxViewModelRequest";
        protected FragmentHostRegistrationSettings _fragmentHostRegistrationSettings;
        protected Lazy<IMvxNavigationSerializer> _lazyNavigationSerializerFactory;

        public MvxFragmentsPresenter(IEnumerable<Assembly> AndroidViewAssemblies);

        protected IMvxNavigationSerializer Serializer { get; }

        public sealed override void Close(IMvxViewModel viewModel);
        public sealed override void Show(MvxViewModelRequest request);
        public void Show(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest);
        protected virtual void CloseActivity(IMvxViewModel viewModel);
        protected virtual void CloseFragment(IMvxViewModel viewModel);
        protected IMvxFragmentHost GetActualFragmentHost();
        protected virtual void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null);
        protected virtual void ShowFragment(MvxViewModelRequest request);
    }
}
查看代碼

仿微信的首頁來一發

好了,對MvvmCross對Fragment的支持對象咱們已經介紹完畢,下面我就動手作一個Fragment的示例,咱們就仿照微信的主窗口來試一下app

  • 首先,定義好宿主,咱們用上一節使用的Sample,修改一下主窗口的佈局,下部爲四個導航按鈕,其他部分爲當前功能模塊的顯示窗口,功能模塊經過Fragment方式進行展現
using Android.App;
using Android.OS;
using Android.Widget;
using MvvmCross.Droid.Views;
using MvxSample.ViewModels;

namespace MvxSample.Droid.Views
{
    [Activity(Label = "MainView", MainLauncher = false, Theme ="@android:style/Theme.Light.NoTitleBar")]
    public class MainView : MvvmCross.Droid.FullFragging.Caching.MvxCachingFragmentActivity<MainViewModel>
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            SetContentView(Resource.Layout.MainPage);

            var grp = FindViewById<RadioGroup>(Resource.Id.main_rg_toolbar);
            grp.CheckedChange += (s, e) =>
            {
                var btn = FindViewById<RadioButton>(e.CheckedId);
                if (btn.Checked == false) return;
                if (e.CheckedId == Resource.Id.main_rb_chat)
                {
                    ViewModel.ShowChat();
                }
                else if (e.CheckedId == Resource.Id.main_rb_friends)
                {
                    ViewModel.ShowFriends();
                }
                else if (e.CheckedId == Resource.Id.main_rb_extras)
                {
                    ViewModel.ShowExtras();
                }
                else if (e.CheckedId == Resource.Id.main_rb_my)
                {
                    ViewModel.ShowMy();
                }
            };
            ViewModel.ShowChat();
        }
    }
}
查看代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:id="@+id/main_container"
        android:layout_width="match_parent"
        android:layout_weight="10"
        android:layout_height="match_parent" />
    <RadioGroup
        android:minHeight="50dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layoutMode="clipBounds"
        android:id="@+id/main_rg_toolbar"
        android:layout_weight="1">
        <RadioButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:checked="true"
            android:text="微信"
            android:gravity="center"
            android:layout_weight="1"
            android:button="@null"
            android:background="@drawable/radiobtn"
            android:id="@+id/main_rb_chat" />
        <RadioButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="聯繫人"
            android:gravity="center"
            android:layout_weight="1"
            android:button="@null"
            android:background="@drawable/radiobtn"
            android:id="@+id/main_rb_friends" />
        <RadioButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="發現"
            android:gravity="center"
            android:layout_weight="1"
            android:button="@null"
            android:background="@drawable/radiobtn"
            android:id="@+id/main_rb_extras" />
        <RadioButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="我"
            android:gravity="center"
            android:layout_weight="1"
            android:button="@null"
            android:background="@drawable/radiobtn"
            android:id="@+id/main_rb_my" />
    </RadioGroup>
</LinearLayout>
查看代碼
  • 下來,咱們定義好要展現的Fragment及佈局
namespace MvxSample.Droid.Views
{
    [MvxFragment(typeof(MainViewModel), Resource.Id.main_container)]
    [Register("mvxsample.droid.views.ChatFragment")]
    public class ChatFragment: MvxFragment<ChatViewModel>
    {
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            var ignore = base.OnCreateView(inflater, container, savedInstanceState);

            var view = this.BindingInflate(Resource.Layout.ChatFragment, container, false);
            return view;
        }
    }
}
查看代碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_purple">
    <RelativeLayout
        android:background="@android:drawable/screen_background_dark_transparent"
        android:layout_alignParentTop="true"
        android:layout_height="50dp"
        android:layout_width="match_parent">
        <TextView
            android:id="@+id/chat_top_title"
            android:allowUndo="true"
            android:layout_centerInParent="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="微信"
            android:textSize="20dip"
            android:gravity="center"
            android:textColor="@android:color/black" />
    </RelativeLayout>
</RelativeLayout>
查看代碼

按照定義好的ChatFragment,咱們定義其它的幾個Fragment,分別爲FriendsFragment、ExtrasFragment、MyFragment。框架

  • 在Setup重載方法 CreateViewPresenter:
namespace MvxSample.Droid
{
    public class Setup : MvxAndroidSetup
    {
        public Setup(Context applicationContext) : base(applicationContext)
        {

        }

        protected override IMvxApplication CreateApp()
        {
            return new App();
        }

        protected override IMvxAndroidViewPresenter CreateViewPresenter()
        {
            var mvxFragmentsPresenter = new MvxFragmentsPresenter(AndroidViewAssemblies);
            Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxFragmentsPresenter);
            return mvxFragmentsPresenter;
        }
    }
}
查看代碼
  • OK,所有代碼就完成了,咱們運行一下看看效果吧Smile

demo3

咱們能夠看到,根據選中的導航項不時,會展現不一樣的Fragment的內容。mvvm

小結

這一節咱們講解了Framgent在MvvmCross的應用。包括宿主窗口的定義,Fragment的定義以及如何在Setup中使用MvxFragmentPresenter。ide

代碼奉上:https://github.com/3368aa/MvxSample

相關文章
相關標籤/搜索