想要通过 FragmentTabHost 实现如下的 TAB 效果:


215325107.png


因 Fragment 会对于每一个 addTab 的 Fragment 进行绘制,且会捕捉 TAB 项的点击事件,因此参考 FragmentTabHost 新增了不绘制,不捕捉指定 tag 的 TAB 的点击事件的 TAB 列表,以及改写 doTabChange() 方法,如下代码:


public class MabFragmentTabHost 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 OnTabChangeListener mOnTabChangeListener;
    private TabInfo mLastTab;
    private boolean mAttached;
    /**
     * 存储不需要被 Attach 到 window 以及不响应TAB被点击事件
     */
    private final ArrayList<String> mNoTabChangedTags = new ArrayList<String>();
    public void addNoTabChangedTag(String tag)
    {
        mNoTabChangedTags.add(tag);
    }
                                      
    ... ...
                                      
    @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;
                                          
        // 在初始 attach 至 windows
        ft = doTabChanged(currentTab, ft);
        if (ft != null)
        {
            ft.commit();
            mFragmentManager.executePendingTransactions();
        }
    }
                                      
    @Override
    public void onTabChanged(String tabId)
    {
        if (mAttached)
        {
            // 当 TAB 列表状态更新时回调
            FragmentTransaction ft = doTabChanged(tabId, null);
            if (ft != null)
            {
                ft.commit();
            }
        }
        if (mOnTabChangeListener != null)
        {
            mOnTabChangeListener.onTabChanged(tabId);
        }
    }
                                      
    ...
                                      
    private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
        // if tag is no-tab-changed
        // then return null
        for (int idx = 0; idx < mNoTabChangedTags.size(); ++idx) {
            if (mNoTabChangedTags.get(idx).equals(tabId)) {
                return null;
            }
        }
                                          
        TabInfo newTab = null;
        for (int i=0; i<mTabs.size(); i++) {
            TabInfo tab = mTabs.get(i);
            if (tab.tag.equals(tabId)) {
                newTab = tab;
            }
        }
                                          
        ... ...
                                          
        return ft;
    }
};


下面看一下在 MainActivity 中的实现:


public class MainActivity extends FragmentActivity {
    private MabFragmentTabHost tabHost;
    public static final String TAB_SPEC_TAB[] = {
        "tab1", "tab2", "tab3", "tab4", "tab5"
    };
    public static final String KEY_TAB_IDX = "key-idx";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tabHost = (MabFragmentTabHost) findViewById(android.R.id.tabhost);
        tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        View viewTab;
        TextView tvTitle;
        ImageView ivIcon;
        for (int idx = 0; idx < 5; ++idx)
        {
            if (idx == 2)
            {
                // 中间 TAB(只是占了位)
                viewTab = getLayoutInflater().inflate(R.layout.tab_icon, null);
                tabHost.addTab(tabHost.newTabSpec(TAB_SPEC_TAB[idx])
                        .setIndicator(viewTab), NormalFragment.class, null);
                // 将此 TAB 加入到 TabHost 的 no-tab-changed 列表
                tabHost.addNoTabChangedTag(TAB_SPEC_TAB[idx]);
            }
            else
            {
                viewTab = getLayoutInflater().inflate(R.layout.tab_normal, null);
                tvTitle = (TextView) viewTab.findViewById(android.R.id.title);
                tvTitle.setText("Tab" + (idx+1));
                ivIcon = (ImageView) viewTab.findViewById(android.R.id.icon);
                ivIcon.setImageResource(android.R.drawable.ic_media_next);
                Bundle args = new Bundle();
                args.putInt(KEY_TAB_IDX, idx+1);
                tabHost.addTab(tabHost.newTabSpec(TAB_SPEC_TAB[idx])
                        .setIndicator(viewTab), NormalFragment.class, args);
            }
        }
        // 中间按键图片触发
        ImageView ivAdd = (ImageView) findViewById(R.id.add_iv);
        ivAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "click icon", Toast.LENGTH_SHORT).show();
            }
        });
    }
}


下面为 activity_main.xml 布局文件


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".MainActivity">
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
        <FrameLayout
                android:id="@+id/realtabcontent"
                android:layout_width="match_parent"
                android:layout_height="0dip"
                android:layout_weight="1"/>
        <com.test.demo.fragtabdemo.MabFragmentTabHost
                android:id="@android:id/tabhost"
                android:layout_gravity="bottom"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            <LinearLayout
                    android:orientation="vertical"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
                <TabWidget
                        android:id="@android:id/tabs"
                        android:orientation="horizontal"
                        android:layout_width="match_parent"
                        android:layout_height="@dimen/DefaultTabWidgetTextHeight"
                        android:divider="@null"
                        android:layout_weight="0"/>
                <FrameLayout
                        android:id="@android:id/tabcontent"
                        android:layout_width="0dip"
                        android:layout_height="0dip"
                        android:layout_weight="0"/>
            </LinearLayout>
        </com.test.demo.fragtabdemo.MabFragmentTabHost>
    </LinearLayout>
    <ImageView android:layout_height="64.0dip"
               android:layout_width="wrap_content"
               android:layout_gravity="bottom|center_horizontal"
               android:id="@+id/add_iv"
               android:src="@drawable/ic_add"/>
</FrameLayout>