美文网首页AndroidAndroid开发实战总结Android开发随笔
如何自定义FragmentTabHost中某一个Tab的点击效果

如何自定义FragmentTabHost中某一个Tab的点击效果

作者: dongorigin | 来源:发表于2015-05-26 00:29 被阅读4753次

    问题

    iOS上的Tab Bar相信大家都很熟悉了,就是界面底部几个按钮,点击可以切换子页面。
    而在Android上,可以用support v4中的FragmentTabHost来实现类似效果,它继承自TabHost,每个子页面都是一个Fragment
    今天遇到一个需求,需要在点击Tab按钮后,不切换子页面,而是跳转到一个新的页面。通过查阅文档,FragmentTabHost与其父类TabHost似乎都没有提供相关函数可以自定义Tab的点击事件。只有一个当Tab切换完成后的回调监听OnTabChangeListener,但是切换已经完成为时已晚啊。
    在查阅文档无果后,我祭出了Google,但是却苦于不知道该如何组织关键词(英文不会,中文离谱),试了几个关键词依然无果。既然如此,就尝试看下源码吧,没想到最终还是非常简单就可以解决问题,遂记录一下。

    首先我们来看一下FragmentTabHost的基本使用,来自官方文档

    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的处理后,继续调用父类TabHostaddTab方法。

    public class FragmentTabHost extends TabHost {
    
        public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
            ...    
            addTab(tabSpec);
        }
    
    }
    

    然后来到TabHost,其中成员变量mTabWidget是Tab的容器。在addTab方法中,先取出了Tab的View,然后执行mTabWidget的addView,将Tab添加到容器中。

    public class TabHost extends FrameLayout {
        private TabWidget mTabWidget;
    
        public void addTab(TabSpec tabSpec) {
            ...
            View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
            ...
            mTabWidget.addView(tabIndicator);
            ...
        }
    
    }
    

    最后来到TabWidget,可以看到它继承自我们的老朋友LinearLayout,这为Tab View提供了线性排布。在addView方法的最后,我们找到了为每个Tab设置点击监听的地方。

    public class TabWidget extends LinearLayout {
    
        @Override
        public void addView(View child) {
            ...
            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);
        }
    
    }
    

    解决问题

    通过一路追踪源码,现在我们已经知道了FragmentTabHost是如何设定每个Tab的点击事件的。最后设置监听器的地方给了我启发,假如能够获取到Tab View,就可以设置自己的点击监听,同时覆盖掉了系统的监听器,从而完成自定义点击效果的任务。
    于是从TabWidget反过来查找获取Tab View的方法。首先TabWidget提供了getChildTabViewAt(int index)方法,可以根据Tab的索引获取到Tab View。然后通过TabHostgetTabWidget可以获取到TabWidget 。得到目标Tab View后,设定自己的OnClickListener,搞定任务。
    下面代码演示了设置第一个Tab点击事件的方法。

    mTabHost.getTabWidget().getChildTabViewAt(0).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            
        }
    });
    

    总结

    系统的源码真的写的非常清楚,只要肯耐心看,很多问题都可以迎刃而解。

    相关文章

      网友评论

      • 繁体字遇上简体字:很不错的解决了我的问题谢谢
      • 37d5fc52de9e:mTabhost.getTabWidget()报空指针啊
      • 8a07d6909945:我想根据点击的tab项在activity当中添加不同的toolbar怎么办
      • 村口滕师傅:非常感谢作者,正愁怎么解决这个问题,再次感谢!
      • hackest:只记录你要点击tab的位置再去监听不行么?int pos=mTabhost.getCurrentTab
        dongorigin:@hackest 看需求,这个解决的需求是点击后tab不切换
      • dongorigin:@cyning 喜欢就帮我点个赞吧,第一篇技术博客求鼓励 :smile:
      • 码上新视界:棒棒的 多些这样的实用的博文谢谢投递

      本文标题:如何自定义FragmentTabHost中某一个Tab的点击效果

      本文链接:https://www.haomeiwen.com/subject/jcjrqttx.html