如何防止SupportV4(片段)Tabhost在TabChange创建自己的片段?

时间:2015-04-24 08:47:20

标签: android android-fragments xamarin mvvmcross

我在SupportV4 tabhost中的片段有问题,它在单个标签更改期间加载了两个片段。 (使用Tabhost; android / support / v4 / app / FragmentTabHost)

问题发生是因为我想使用MVVMCross及其ViewModel,所以我需要在Fragments中加载ViewModels(在选项卡内)。

为了清理,我使用了以下流程; - 加载ActionActivity,然后加载Fragment以保存Tabs - AddTabs(片段内) - 使用SupportFragmentManager

添加Fragment的每个TabChange开关

包含标签的My Fragment具有以下内容:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    var ignored = base.OnCreateView(inflater, container, savedInstanceState);
    var rootView = this.BindingInflate(LayoutId, null);

    activityTabHost = (FragmentTabHost) rootView.FindViewById(Android.Resource.Id.TabHost);
    activityTabHost.Setup(Activity, ChildFragmentManager, Resource.Id.realtabcontent);

    var savedcurrentTabTag = string.Empty;

    AddTabs(savedInstanceState);

    if (savedInstanceState != null) {
        savedcurrentTabTag = savedInstanceState.GetString(SavedTabIndexStateKey);
        activityTabHost.SetCurrentTabByTag(savedcurrentTabTag);
    }

    if (lookup.Any()) {
        OnTabChanged(string.IsNullOrWhiteSpace(savedcurrentTabTag) ? lookup.First().Key : savedcurrentTabTag);
    }

    activityTabHost.SetOnTabChangedListener(this);

    return rootView;
}

TabLoading(逐个)

private static void AddTab(Fragment fragment, // Check incomming (was MvxTabsFragmentActivity)
TabHost tabHost,
Android.Widget.TabHost.TabSpec tabSpec,
MvxTabFragmentInfo tabInfo) {
    // Attach a Tab view factory to the spec
    tabSpec.SetContent(new MvxTabFragmentFactory(fragment.Activity));
    var tag = tabSpec.Tag;

    // Check to see if we already have a CachedFragment for this tab, probably
    // from a previously saved state.  If so, deactivate it, because our
    // initial state is that a tab isn't shown.
    tabInfo.CachedFragment = fragment.ChildFragmentManager.FindFragmentByTag(tag);
    if (tabInfo.CachedFragment != null && !tabInfo.CachedFragment.IsDetached) {
        var ft = fragment.ChildFragmentManager.BeginTransaction();
        ft.Detach(tabInfo.CachedFragment);
        ft.Commit();
        fragment.ChildFragmentManager.ExecutePendingTransactions();
    }

    tabHost.AddTab(tabSpec, Class.FromType(tabInfo.FragmentType), tabInfo.Bundle);
}

标签更改:

public virtual void OnTabChanged(string tag) {
    var newTab = lookup[tag];
    if (currentTab != newTab) {
        var ft = ChildFragmentManager.BeginTransaction();
        OnTabFragmentChanging(tag, ft);
        if (currentTab != null) {
            if (currentTab.CachedFragment != null) {
                ft.Detach(currentTab.CachedFragment);
            }
        }

        if (newTab != null) {
            if (newTab.CachedFragment == null) {
                // CAUTION!!!
                // This adds a NEW fragment to the ChildFragmentManager, but the TabHost creates its own Fragment to! 
                // (that one needs to be cancled, regocnized by the lack of a ViewModel)
                newTab.CachedFragment = Instantiate(Activity, FragmentJavaName(newTab.FragmentType), newTab.Bundle);
                FixupDataContext(newTab);
                ft.Add(TabContentId, newTab.CachedFragment, newTab.Tag);
            } else {
                FixupDataContext(newTab);
                ft.Attach(newTab.CachedFragment);
            }
        }

        currentTab = newTab;
        currentTabTag = (newTab != null) ? newTab.Tag : string.Empty;
        ft.Commit();
        ChildFragmentManager.ExecutePendingTransactions();
    }

    TabHost.ViewTreeObserver.RemoveOnTouchModeChangeListener(TabHost);
}

如您所见,我目前正在加载自己的Fragment,然后将ViewModel附加到Fragment。很高兴说ViewModel已经存在,它来自一个包含4个ViewModel的父ViewModel,每个Tab都有一个。

BUT! TabHost在TabChange期间创建了自己的Fragment,但没有ViewModel,因为它没有自动加载到MvxFragment中。

这是我的解决方法,取消了没有ViewModel的Fragment (否则我会在彼此之上找到碎片)。

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (ViewModel == null) {
        return null;
    }

    base.OnCreateView(inflater, container, savedInstanceState);
    return this.BindingInflate(Resource.Layout.GroupedFragmentView, null);
}

这是一个解决方法,我希望能够更多地控制创建片段的Tabhost。

有谁知道如何进入SupportV4 tabhost来控制片段创建?或者其他任何人都有一个很好的解决方案,而不是我的解决方法?

1 个答案:

答案 0 :(得分:1)

答案是解决方法; (但更好的解决方案是Cheesebaron的建议)

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    if (ViewModel == null)
    {
        return null;
    }

    base.OnCreateView(inflater, container, savedInstanceState);
    return this.BindingInflate(Resource.Layout.GroupedFragmentView, null);
}