仿 QQ 底部 tab 导航

Posted changhaiSmile

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿 QQ 底部 tab 导航相关的知识,希望对你有一定的参考价值。

仿 QQ 底部 tab 导航

原文链接: 本篇博客主要实现以下效果: 使用 FragmentTabHost 实现 qq 底部 Tab 切换 使用 RadioGroup 和 RadioButton 实现仿 qq 底部切换 使用 RadioGroup 和 ViewPager 实现可以滑动切换的仿 qq 底部 Tab 切换 解决 Fragment 多次实例化的几种方案 Fragemnt 的懒加载(网上很多人称之为 Fragemnt 的最优加载) —— 由   分享

本篇博客主要实现以下效果:

  • 使用FragmentTabHost实现qq底部Tab切换
  • 使用RadioGroup和RadioButton实现仿qq底部切换
  • 使用RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab切换
  • 解决Fragment多次实例化的几种方案
  • Fragemnt的懒加载(网上很多人称之为Fragemnt的最优加载)

效果图

老规矩,废话 不多说,先看效果图

FragmentTabHost实现qq底部Tab实践的效果图


RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab效果图


使用FragmentTabHost实现qq底部Tab切换

第一步先看布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">
    <!--用来填充Fragemnt的FrayLayout-->
    <FrameLayout
        android:id="@+id/main_layout_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </FrameLayout>
    <!--FragmentTabHost-->
    <android.support.v4.app.FragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#F6F6F6"
        android:paddingBottom="5dp"
        android:paddingTop="5dp">

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp"/>
    </android.support.v4.app.FragmentTabHost>

</LinearLayout>

其实很简单,没什么好说的 ,就是一个vertical的LinearLayout中放置着一个FrameLayout和FragmentTabHost

接下来我们来看一下代码

public class FirstStyleActivity extends AppCompatActivity 
    FragmentTabHost mTabHost;
    private TabWidget mTabWidget;
    private List<FragmentInfo> mFragmentEntities;
    private static final String TAG = "xujun";
    private static final String tag = "tag";
    public static final String[] mTiltles = new String[]
            "首页", "课程", "直播", "个人"
    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first_style);
        mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);

        mTabHost.setup(this, getSupportFragmentManager(), R.id.main_layout_content);
        mTabWidget = mTabHost.getTabWidget();
        //  去掉分割线
        mTabWidget.setDividerDrawable(null);
        mFragmentEntities = MainFragmentFactory.getInstance().getList();
        initListener();
        initData();
    

    private void initData() 
        int size = mFragmentEntities.size();
        for (int i = 0; i < size; i++) 
            Log.i(TAG, "size:=" + size);
            FragmentInfo fragmentInfo = mFragmentEntities.get(i);
            String title = fragmentInfo.getTitle();
            TabHost.TabSpec tabSpec = mTabHost.newTabSpec(title).setIndicator(getTabView
                    (i));
            Bundle bundle = new Bundle();
            bundle.putString(tag, mTiltles[i]);

            mTabHost.addTab(tabSpec, fragmentInfo.getClz(), bundle);
        
        updateTab(0);
    

    private void initListener() 
        mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() 
            @Override
            public void onTabChanged(String tabId) 
                int currentTab = mTabHost.getCurrentTab();
                Log.i(TAG, "onTabChanged:currentTab:=" + currentTab);
                updateTab(currentTab);
            
        );
    

    private View getTabView(int i) 
        View view = View.inflate(this, R.layout.tab_layout, null);
        int currentTab = mTabHost.getCurrentTab();
        Log.i(TAG, "currentTab:=" + currentTab);
        setSingleView(view, currentTab, i);
        return view;
    

    private void setSingleView(View view, int currentTab, int index) 
        FragmentInfo fragmentInfo = mFragmentEntities.get(index);
        int[] imagIds = fragmentInfo.getImagIds();
        int[] colors = fragmentInfo.getColors();
        TextView tv = (TextView) view.findViewById(R.id.tab_tv);
        ImageView iv = (ImageView) view.findViewById(R.id.tab_icon);
        tv.setText(fragmentInfo.getTitle());
        Resources resources = getResources();
        if (index == currentTab) 

            tv.setTextColor(resources.getColor(colors[1]));
            iv.setImageDrawable(resources.getDrawable(imagIds[1]));
         else 
            tv.setTextColor(getResources().getColor(colors[0]));
            iv.setImageDrawable(resources.getDrawable(imagIds[0]));
        
    

    private void updateTab(int currentTab) 

        int childCount = mTabWidget.getChildCount();
        for (int i = 0; i < childCount; i++) 
            View view = mTabWidget.getChildTabViewAt(i);
            setSingleView(view, currentTab, i);

        
    

其实说起来也很简单,主要分为以下步骤

  • 第一步,实例化FragmentTabHost并设置相关样式
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);

mTabHost.setup(this, getSupportFragmentManager(), R.id.main_layout_content);
mTabWidget = mTabHost.getTabWidget();
//  去掉分割线
mTabWidget.setDividerDrawable(null);
 for (int i = 0; i < size; i++) 
    Log.i(TAG, "size:=" + size);
    FragmentInfo fragmentInfo = mFragmentEntities.get(i);
    String title = fragmentInfo.getTitle();
    TabHost.TabSpec tabSpec = mTabHost.newTabSpec(title).setIndicator(getTabView
            (i));
    Bundle bundle = new Bundle();
    bundle.putString(tag, mTiltles[i]);

    mTabHost.addTab(tabSpec, fragmentInfo.getClz(), bundle);
  • 第三步,通过设置 监听器来实现底部tab颜色和图案样式的转换
 mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() 
    @Override
    public void onTabChanged(String tabId) 
        int currentTab = mTabHost.getCurrentTab();
        Log.i(TAG, "onTabChanged:currentTab:=" + currentTab);
        updateTab(currentTab);
    
);

运行上述代码及可以看到如下效果图


使用RadioGroup和RadioButton实现仿qq底部切换

第一步 ,先看布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/activity_second_style"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>
    <!--用来填充Fragemnt的FrayLayout-->
    <FrameLayout
        android:id="@+id/fl"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

    </FrameLayout>
    <!--使用RadioGroup来实现tab的切换-->
    <RadioGroup

        android:id="@+id/rg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
    >
        <RadioButton
            android:id="@+id/rb_home"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_home"
            android:text="首页"/>

        <RadioButton
            android:id="@+id/rb_course"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_course"
            android:text="课程"/>

        <RadioButton
            android:id="@+id/rb_direct_seeding"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_direct_seeding"
            android:text="直播"/>

        <RadioButton
            android:id="@+id/rb_me"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_me"
            android:text="我的"/>

    </RadioGroup>

</LinearLayout>

其实每一个tab的选中时利用RadioGroup中RadioButton的互相排斥的特性,即每一次只能选中一个 RadioButton

至于bottom_tab的style,只不过是将相同的arr提取出来,减少布局的代码量和方便统一修改而已,平时我们在写布局代码 的时候也可以这样

<style name="bottom_tab">
    <item name="android:layout_width" >0dp</item>
    <item name="android:layout_height" >wrap_content</item>
    <item name="android:layout_weight" >1</item>
    <item name="android:text" >0dp</item>
    <item name="android:gravity" >center</item>
    <item name="android:textColor" >@drawable/sel_bottom_tab_text</item>
    <item name="android:padding" >8dp</item>
    <item name="android:button" >@null</item>
</style>

第二步,我们来看一下Activity的 代码

public class ThreeActivity extends AppCompatActivity 

    FrameLayout mFl;
    RadioGroup mRg;
    private FragmentManager mFragmentManager;

    private int position = 0;

    public static final String[] mTiltles = new String[]
            "首页", "课程", "直播", "个人"
    ;
    private List<Fragment> mFragments;
    private Fragment mCurFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_three);
        mFl = (FrameLayout) findViewById(R.id.fl);
        mRg = (RadioGroup) findViewById(R.id.rg);
        mFragments = new ArrayList<>();
        for (int i = 0; i < mTiltles.length; i++) 
            ItemFragement itemFragement = ItemFragement.newInstance(mTiltles[i]);
            mFragments.add(itemFragement);
        
        mCurFragment = mFragments.get(position);
        replaceFragment(mCurFragment);

        ((RadioButton)mRg.getChildAt(position)).setChecked(true);

        initListener();
    

    private void initListener() 
        mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() 

            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) 

                RadioButton radioButton = (RadioButton) group.findViewById(checkedId);

                if (false == radioButton.isChecked()) 
                    return;
                


                switch (checkedId) 
                    case R.id.rb_home:
                        position = 0;
                        break;

                    case R.id.rb_course:
                        position = 1;
                        break;

                    case R.id.rb_direct_seeding:
                        position = 2;
                        break;

                    case R.id.rb_me:
                        position = 3;
                        break;
                    default:
                        position = 0;
                        break;

                
                LUtils.i("position==" + position);

                Fragment to = mFragments.get(position);
                showFragment(mCurFragment, to);
                mCurFragment = to;

            

        );
    

    private void showFragment(Fragment from, Fragment to) 
        FragmentManager supportFragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = supportFragmentManager.beginTransaction();
        if (!to.isAdded())     // 先判断是否被add过
            transaction.hide(from).add(R.id.fl, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
         else 
            transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
        

    

    /**
     * 这个方法用老替换fragment
     * xujun
     * 2016/5/3 17:28.
     */

    private void replaceFragment(Fragment fragmeny) 
        FragmentManager supportFragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fl, fragmeny).commit();
    

思路解析

  • 实例化各个控件,这里代码就不贴出来了
  • 初始化 Fragemnt 和选中各个tab
 mFragments = new ArrayList<>();
for (int i = 0; i < mTiltles.length; i++) 
    ItemFragement itemFragement = ItemFragement.newInstance(mTiltles[i]);
    mFragments.add(itemFragement);

mCurFragment = mFragments.get(position);
replaceFragment(mCurFragment);

((RadioButton)mRg.getChildAt(position)).setChecked(true);

private void replaceFragment(Fragment fragmeny) 
    FragmentManager supportFragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
    fragmentTransaction.replace(R.id.fl, fragmeny).commit();
  • 第三步,通过监听RadioGroup的 OnCheckedChangeListener事件,来实现tab和Fragemnt的切换
 mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() 

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) 

        RadioButton radioButton = (RadioButton) group.findViewById(checkedId);

        if (false == radioButton.isChecked()) 
            return;
        


        switch (checkedId) 
            case R.id.rb_home:
                position = 0;
                break;

            case R.id.rb_course:
                position = 1;
                break;

            case R.id.rb_direct_seeding:
                position = 2;
                break;

            case R.id.rb_me:
                position = 3;
                break;
            default:
                position = 0;
                break;

        
        LUtils.i("position==" + position);

        Fragment to = mFragments.get(position);
        showFragment(mCurFragment, to);
        mCurFragment = to;

    

);

使用RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab切换

第一步,我们 同样先看布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/activity_second_style"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>
    <!--用来填充Fragemnt的ViewPager-->
    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

    </android.support.v4.view.ViewPager>
    <!--使用RadioGroup来实现tab的切换-->
    <RadioGroup

        android:id="@+id/rg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
    >
        <RadioButton
            android:id="@+id/rb_home"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_home"
            android:text="首页"/>

        <RadioButton
            android:id="@+id/rb_course"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_course"
            android:text="课程"/>

        <RadioButton
            android:id="@+id/rb_direct_seeding"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_direct_seeding"
            android:text="直播"/>

        <RadioButton
            android:id="@+id/rb_me"
            style="@style/bottom_tab"
            android:drawableTop="@drawable/sel_me"
            android:text="我的"/>

    </RadioGroup>

</LinearLayout>

第二步,我们一起来看一下Activity代码

public class SecondStyleActivity extends AppCompatActivity 

    public static final String[] mTiltles = new String[]
            "首页", "课程", "直播", "个人"
    ;
    private List<Fragment> mFragments;
    ViewPager mViewPager;
    RadioGroup mRg;
    private int position = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second_style);
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
        mRg = (RadioGroup) findViewById(R.id.rg);
        ini

以上是关于仿 QQ 底部 tab 导航的主要内容,如果未能解决你的问题,请参考以下文章

android 底部tab 求大神帮写个

微信小程序(底部导航的实现)

lottie动画实战(仿汽车之家底部Tab切换动画)

Android 高仿华为手机Tab页滑动导航效果

Android仿小米商城底部导航栏之二(BottomNavigationBarViewPager和Fragment的联动使用)

Android底部导航BottomNavigationBar