看下源码吧,源源码还是非常简单就可以解决问题,遂记录一下。
首先我们来看一下 FragmentTabHost 的基本使用,来自 官方文档(http://developer.android.com/reference/android/support/v4/app/FragmentTabHost.html)
mTabHost = new FragmentTabHost(getActivity()); mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1); mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), FragmentStackSupport.CountingFragment.class, null); mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"), LoaderCursorSupport.CursorLoaderListFragment.class, null);第二行通过 setup 进行初始化,三四行通过 addTab 方法添加了两个Tab,我们就从Tab的添加入手,开始追踪源码,看看它是如何设置每个Tab的点击事件的。
首先是 FragmentTabHost ,它继承自 TabHost ,增加了一个 addTab 的重载方法,第二个参数接收Fragment的class,用于Fragment相关逻辑。在完成对Fragment的处理后,继续调用父类 TabHost 的 addTab 方法。
首先是 FragmentTabHost ,它继承自 TabHost ,增加了一个 addTab 的重载方法,第二个参数接收Fragment的class,用于Fragment相关逻辑。在完成对Fragment的处理后,继续调用父类 TabHost 的 addTab 方法。
public class FragmentTabHost extends TabHost { 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); } }然后来到 TabHost ,其中成员变量 mTabWidget 是Tab的容器。在 addTab 方法中,先取出了Tab的View,然后执行mTabWidget的addView,将Tab添加到容器中。
public class TabHost extends FrameLayout { private TabWidget mTabWidget; /** * Add a tab. * @param tabSpec Specifies how to create the indicator and content. */ public void addTab(TabSpec tabSpec) { if (tabSpec.mIndicatorStrategy == null) { throw new IllegalArgumentException("you must specify a way to create the tab indicator."); } if (tabSpec.mContentStrategy == null) { throw new IllegalArgumentException("you must specify a way to create the tab content"); } View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView(); tabIndicator.setOnKeyListener(mTabKeyListener); // If this is a custom view, then do not draw the bottom strips for // the tab indicators. if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) { mTabWidget.setStripEnabled(false); } mTabWidget.addView(tabIndicator); mTabSpecs.add(tabSpec); if (mCurrentTab == -1) { setCurrentTab(0); } } }最后来到 TabWidget ,可以看到它继承自我们的老朋友LinearLayout,这为Tab View提供了线性排布。在 addView 方法的最后,我们找到了为每个Tab设置点击监听的地方。
public class TabWidget extends LinearLayout { @Override public void addView(View child) { if (child.getLayoutParams() == null) { final LinearLayout.LayoutParams lp = new LayoutParams( 0, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f); lp.setMargins(0, 0, 0, 0); child.setLayoutParams(lp); } // Ensure you can navigate to the tab with the keyboard, and you can touch it child.setFocusable(true); child.setClickable(true); super.addView(child); // TODO: detect this via geometry with a tabwidget listener rather // than potentially interfere with the view's listener child.setOnClickListener(new TabClickListener(getTabCount() - 1)); child.setOnFocusChangeListener(this); } }为了解决Tabhost的点击监听事件的发生,通过一路追踪源码,现在我们已经知道了 FragmentTabHost 是如何设定每个Tab的点击事件的。最后设置监听器的地方给了我启发,假如能够获取到Tab View,就可以设置自己的点击监听,同时覆盖掉了系统的监听器,从而完成自定义点击效果的任务。
mTabHost.getTabWidget().getChildTabViewAt(0).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } });总结:源码中还有很多可以用到的方法,大家如果需要可以自己去了解一下源码。