Android FragmentTabHost - Not fully baked yet?

前端 未结 4 445
南笙
南笙 2020-12-10 02:21

I wanted to see if anyone has had success with customization of tabs using FragmentTabHost that comes with the new Android API level 17.

I was excited to be able to

4条回答
  •  既然无缘
    2020-12-10 02:46

    I finally got to the bottom of this. There is an issue with FragmentTabHost.java which will always create a TabHost element for you, no matter what you define in XML and inflate beforehand.

    As such, I commented out that part of code when writing my own version of FragmentTabHost.java.

    Make sure to use your new version of this in your XML layout,

    And of course inflate it:

    Fragment1.java:

    mTabHost = (MyFragmentTabHost) view.findViewById(android.R.id.tabhost);
    mTabHost.setup(getActivity(), getChildFragmentManager(), android.R.id.tabcontent);
    

    MyFragmentTabHost.java:

    package com.example.app;
    
    import java.util.ArrayList;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.os.Bundle;
    import android.os.Parcel;
    import android.os.Parcelable;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.util.AttributeSet;
    import android.view.View;
    import android.widget.FrameLayout;
    import android.widget.TabHost;
    
    /**
     * Special TabHost that allows the use of {@link Fragment} objects for
     * its tab content.  When placing this in a view hierarchy, after inflating
     * the hierarchy you must call {@link #setup(Context, FragmentManager, int)}
     * to complete the initialization of the tab host.
     *
     */
    public class MyFragmentTabHost extends TabHost
        implements TabHost.OnTabChangeListener {
    private final ArrayList mTabs = new ArrayList();
    private FrameLayout mRealTabContent;
    private Context mContext;
    private FragmentManager mFragmentManager;
    private int mContainerId;
    private TabHost.OnTabChangeListener mOnTabChangeListener;
    private TabInfo mLastTab;
    private boolean mAttached;
    
    static final class TabInfo {
        private final String tag;
        private final Class clss;
        private final Bundle args;
        private Fragment fragment;
    
        TabInfo(String _tag, Class _class, Bundle _args) {
            tag = _tag;
            clss = _class;
            args = _args;
        }
    }
    
    static class DummyTabFactory implements TabHost.TabContentFactory {
        private final Context mContext;
    
        public DummyTabFactory(Context context) {
            mContext = context;
        }
    
        @Override
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }
    
    static class SavedState extends BaseSavedState {
        String curTab;
    
        SavedState(Parcelable superState) {
            super(superState);
        }
    
        private SavedState(Parcel in) {
            super(in);
            curTab = in.readString();
        }
    
        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeString(curTab);
        }
    
        @Override
        public String toString() {
            return "FragmentTabHost.SavedState{"
                    + Integer.toHexString(System.identityHashCode(this))
                    + " curTab=" + curTab + "}";
        }
    
        public static final Parcelable.Creator CREATOR
                = new Parcelable.Creator() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }
    
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
    
    public MyFragmentTabHost(Context context) {
        // Note that we call through to the version that takes an AttributeSet,
        // because the simple Context construct can result in a broken object!
        super(context, null);
        initFragmentTabHost(context, null);
    }
    
    public MyFragmentTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
        initFragmentTabHost(context, attrs);
    }
    
    private void initFragmentTabHost(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,
                new int[] { android.R.attr.inflatedId }, 0, 0);
        mContainerId = a.getResourceId(0, 0);
        a.recycle();
    
        super.setOnTabChangedListener(this);
    
    
        /*** REMOVE THE REST OF THIS FUNCTION ***/
        /*** findViewById(android.R.id.tabs) IS NULL EVERY TIME ***/
    }
    
    /**
     * @deprecated Don't call the original TabHost setup, you must instead
     * call {@link #setup(Context, FragmentManager)} or
     * {@link #setup(Context, FragmentManager, int)}.
     */
    @Override @Deprecated
    public void setup() {
        throw new IllegalStateException(
                "Must call setup() that takes a Context and FragmentManager");
    }
    
    public void setup(Context context, FragmentManager manager) {
        super.setup();
        mContext = context;
        mFragmentManager = manager;
        ensureContent();
    }
    
    public void setup(Context context, FragmentManager manager, int containerId) {
        super.setup();
        mContext = context;
        mFragmentManager = manager;
        mContainerId = containerId;
        ensureContent();
        mRealTabContent.setId(containerId);
    
        // We must have an ID to be able to save/restore our state.  If
        // the owner hasn't set one at this point, we will set it ourself.
        if (getId() == View.NO_ID) {
            setId(android.R.id.tabhost);
        }
    }
    
    private void ensureContent() {
        if (mRealTabContent == null) {
            mRealTabContent = (FrameLayout)findViewById(mContainerId);
            if (mRealTabContent == null) {
                throw new IllegalStateException(
                        "No tab content FrameLayout found for id " + mContainerId);
            }
        }
    }
    
    @Override
    public void setOnTabChangedListener(OnTabChangeListener l) {
        mOnTabChangeListener = l;
    }
    
    public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) {
        tabSpec.setContent(new DummyTabFactory(mContext));
        String tag = tabSpec.getTag();
    
        TabInfo info = new TabInfo(tag, clss, args);
    
        if (mAttached) {
            // If we are already attached to the window, then check to make
            // sure this tab's fragment is inactive if it exists.  This shouldn't
            // normally happen.
            info.fragment = mFragmentManager.findFragmentByTag(tag);
            if (info.fragment != null && !info.fragment.isDetached()) {
                FragmentTransaction ft = mFragmentManager.beginTransaction();
                ft.detach(info.fragment);
                ft.commit();
            }
        }
    
        mTabs.add(info);
        addTab(tabSpec);
    }
    
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    
        String currentTab = getCurrentTabTag();
    
        // Go through all tabs and make sure their fragments match
        // the correct state.
        FragmentTransaction ft = null;
        for (int i=0; i

提交回复
热议问题