2012-11-16 54 views
4

我试图把FragmentTabHost放在屏幕的底部。前一段时间,我可以用普通的TabHost做到这一点(以下是this thread),但现在这不适用于我。Android:与FragmentTabHost底部的标签

有没有办法做到这一点?

谢谢!

+0

所有我发现的建议涉及使用XML布局属性,如在描述那个线程。但是使用FragmentTabHost,这些布局不被使用。也许它必须用代码完成?不知道要调用什么函数。 – jamis0n

+1

如果您想遵循Android设计准则,则不应使用底部的选项卡栏。请参阅http://developer.android.com/design/patterns/pure-android.html – pegel

+0

我在以下链接回答.http://stackoverflow.com/a/14853097/874752 –

回答

0

最后我跟着这个教程:Android Tabs with Fragments

我放弃了与FragmentTabHost,这是比较容易(恕我直言)来实现,我是能够把tabWidget底部没有努力。

+0

该示例显示标签顶部。不在底部 –

6

我终于明白了这一点。 FragmentTabHost.java存在一个问题,无论您在XML中定义了什么并事先膨胀,它总是会为您创建一个TabHost元素。

因此,在编写我自己的FragmentTabHost.java版本时,我注意到了部分代码。

确保在你的XML布局使用这个新版本,<com.example.app.MyFragmentTabHost

,当然还有它充气:

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<TabInfo> mTabs = new ArrayList<TabInfo>(); 
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<SavedState> CREATOR 
      = new Parcelable.Creator<SavedState>() { 
     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<mTabs.size(); i++) { 
     TabInfo tab = mTabs.get(i); 
     tab.fragment = mFragmentManager.findFragmentByTag(tab.tag); 
     if (tab.fragment != null && !tab.fragment.isDetached()) { 
      if (tab.tag.equals(currentTab)) { 
       // The fragment for this tab is already there and 
       // active, and it is what we really want to have 
       // as the current tab. Nothing to do. 
       mLastTab = tab; 
      } else { 
       // This fragment was restored in the active state, 
       // but is not the current tab. Deactivate it. 
       if (ft == null) { 
        ft = mFragmentManager.beginTransaction(); 
       } 
       ft.detach(tab.fragment); 
      } 
     } 
    } 

    // We are now ready to go. Make sure we are switched to the 
    // correct tab. 
    mAttached = true; 
    ft = doTabChanged(currentTab, ft); 
    if (ft != null) { 
     ft.commit(); 
     mFragmentManager.executePendingTransactions(); 
    } 
} 

@Override 
protected void onDetachedFromWindow() { 
    super.onDetachedFromWindow(); 
    mAttached = false; 
} 

@Override 
protected Parcelable onSaveInstanceState() { 
    Parcelable superState = super.onSaveInstanceState(); 
    SavedState ss = new SavedState(superState); 
    ss.curTab = getCurrentTabTag(); 
    return ss; 
} 

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    SavedState ss = (SavedState)state; 
    super.onRestoreInstanceState(ss.getSuperState()); 
    setCurrentTabByTag(ss.curTab); 
} 

@Override 
public void onTabChanged(String tabId) { 
    if (mAttached) { 
     FragmentTransaction ft = doTabChanged(tabId, null); 
     if (ft != null) { 
      ft.commit(); 
     } 
    } 
    if (mOnTabChangeListener != null) { 
     mOnTabChangeListener.onTabChanged(tabId); 
    } 
} 

private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) { 
    TabInfo newTab = null; 
    for (int i=0; i<mTabs.size(); i++) { 
     TabInfo tab = mTabs.get(i); 
     if (tab.tag.equals(tabId)) { 
      newTab = tab; 
     } 
    } 
    if (newTab == null) { 
     throw new IllegalStateException("No tab known for tag " + tabId); 
    } 
    if (mLastTab != newTab) { 
     if (ft == null) { 
      ft = mFragmentManager.beginTransaction(); 
     } 
     if (mLastTab != null) { 
      if (mLastTab.fragment != null) { 
       ft.detach(mLastTab.fragment); 
      } 
     } 
     if (newTab != null) { 
      if (newTab.fragment == null) { 
       newTab.fragment = Fragment.instantiate(mContext, 
         newTab.clss.getName(), newTab.args); 
       ft.add(mContainerId, newTab.fragment, newTab.tag); 
      } else { 
       ft.attach(newTab.fragment); 
      } 
     } 

     mLastTab = newTab; 
    } 
    return ft; 
} 
} 
+0

我在“mTabHost =(MyFragmentTabHost)view.findViewById(android.R.id.tabhost);”出现错误。你能解释为什么吗? – Akhil

+0

请将您的问题发布在代码的新主题中,我将很乐意帮助:) – jamis0n

+0

这是一项了不起的工作!谢谢! – JPMagalhaes

2

放置此代码后,您已设置并将选项卡添加到你的FragmentTabHost,它将删除并添加选项卡作为TabHost中的最后一个子项。 (在嵌套片段与测试从android.support.v13.app.FragmentTabHost XML充气并建立与getChildFragmentManager())

View tabs = (TabWidget) mTabHost.findViewById(android.R.id.tabs); 
ViewGroup parent = (ViewGroup) mTabHost.getChildAt(0); 
parent.removeView(tabs); 
parent.addView(tabs);