android 导航栏实现方式

自从Android3.0引入Fargment之后,在Activity中使用底部导航进行Fragment的切换已经越来越普遍,或者可以说已经成为了移动应用的标配,而本篇文章我总结了项目中常用的几种实现导航的方式,分别是RadioGroup、Tablayout、RadioGroup+反射和FragmentTabHost四种实现方式,包含底部和顶部的双导航界面的实现,实现的结果类似下图所示:
    

      Github下载地址:https://github.com/huohaoliz/BottomNavigation
一、使用RadioGroup+Fragment实现底部导航,使用TabLayout+Fragment实现顶部导航
        1,RadioGroup+Fragment的形式是之前开发中比较受欢迎,使用比较多的一种实现形式,所以把它排到第一位。好了不扯了,直接代码走起:
       首先,在radiogroup.xml中的布局文件是:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.linktestproject.RadioGroupActivity">     <FrameLayout        android:id="@+id/fl_radio_show"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        ></FrameLayout>    <RadioGroup        android:id="@+id/rg_radio_navigation"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="horizontal"        android:layout_gravity="bottom">        <RadioButton            android:id="@+id/rb_radio_homepage"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:drawableTop="@drawable/homepage"            android:text="@string/homepage"            android:button="@null"            android:drawablePadding="5dp"            android:textColor="@drawable/radio_button_selector"            />        <RadioButton            android:id="@+id/rb_radio_subscription"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:drawableTop="@drawable/subscription"            android:text="@string/subscription"            android:button="@null"            android:drawablePadding="5dp"            android:textColor="@drawable/radio_button_selector"            />        <RadioButton            android:id="@+id/rb_radio_find"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:drawableTop="@drawable/find"            android:text="@string/find"            android:button="@null"            android:drawablePadding="5dp"            android:textColor="@drawable/radio_button_selector"            />        <RadioButton            android:id="@+id/rb_radio_mine"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:drawableTop="@drawable/mine"            android:text="@string/mine"            android:button="@null"            android:drawablePadding="5dp"            android:textColor="@drawable/radio_button_selector"            />    </RadioGroup></LinearLayout>
        我们需要对每个RadioButton的图片资源做一个选择器,在drawable文件夹下添加四个选择器,内容是(这是首页的图片选择器,其他与此类似就不贴代码了):

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:state_checked="true" android:drawable="@mipmap/tab4_down"></item>    <item android:state_checked="false" android:drawable="@mipmap/tab4"></item></selector>之后我们还要对选中的RadioButton添加字体颜色的选择器:


<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:state_checked="true" android:color="@color/textChecked"></item>    <item android:state_checked="false" android:color="@color/textUnChecked"></item></selector>之后进入Actiivity中,实现代码:


public class RadioGroupActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {     private RadioGroup mRadioGroup;    private Fragment[] mFragments;    private FrameLayout mLayout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_radio_group);        getSupportActionBar().hide();        initView();        initFragment();        setListener();    }     private void setListener() {        //对RadioGroup设置监听事件(监听点击选择)        mRadioGroup.setOnCheckedChangeListener(this);     }     private void initFragment() {        //初始化要显示的Fragment数组        mFragments=new Fragment[4];        mFragments[0]=new HomepageFragment();        mFragments[1]=new SubscriptionFragment();        mFragments[2]=new FindFragment();        mFragments[3]=new MineFragment();        //获取Fragment管理器        FragmentManager manager=getSupportFragmentManager();        //获取事物(使用v4包下)        FragmentTransaction transaction=manager.beginTransaction();        //默认选中HomepageFragment替换Framelayout        transaction.replace(R.id.fl_radio_show,mFragments[0]);        //提交事物        transaction.commit();        //默认点击首页        mRadioGroup.check(R.id.rb_radio_homepage);    }     private void initView() {        mRadioGroup= (RadioGroup) findViewById(R.id.rg_radio_navigation);        mLayout= (FrameLayout) findViewById(R.id.fl_radio_show);    }     @Override    public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {        //写法与默认点击页面的相同        FragmentManager manager=getSupportFragmentManager();        FragmentTransaction  transaction=manager.beginTransaction();        switch(checkedId){            case R.id.rb_radio_homepage:                transaction.replace(R.id.fl_radio_show,mFragments[0]);            break;            case R.id.rb_radio_subscription:                transaction.replace(R.id.fl_radio_show,mFragments[1]);                break;            case R.id.rb_radio_find:                transaction.replace(R.id.fl_radio_show,mFragments[2]);                break;            case R.id.rb_radio_mine:                transaction.replace(R.id.fl_radio_show,mFragments[3]);                break;        }        transaction.commit();    }}到此底部导航就已经完成,实现效果如下图所示:

       
        2,在HomepageFragment中使用Tablayout+Fragment实现顶部导航
            首先Tablayout是Android5.0发布的Design包中的组件,所以我们在使用之前必须加入Design包的依赖(这里不会就自己百度吧)。然后在Homepage的资源文件中的布局如下:

<LinearLayout 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"    android:orientation="vertical"    xmlns:app="http://schemas.android.com/apk/res-auto"    tools:context="com.example.linktestproject.fragments.HomepageFragment">    <android.support.design.widget.TabLayout        android:id="@+id/tl_homepage_navigation"        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:tabIndicatorColor="@color/colorPrimary"        app:tabSelectedTextColor="@color/textChecked"        app:tabTextColor="@color/textUnChecked"        >    </android.support.design.widget.TabLayout>    <android.support.v4.view.ViewPager        android:id="@+id/vp_homepage_show"        android:layout_width="match_parent"        android:layout_height="match_parent"        >    </android.support.v4.view.ViewPager></LinearLayout> Tablayout的属性(此处只是给出用到的三个属性,其他常用的属性会在Tablayout+Fragment中给出):


  app:tabIndicatorColor="@color/colorPrimary"    //下边指示横线的颜色  app:tabSelectedTextColor="@color/textChecked"  //Text选中的文字颜色 app:tabTextColor="@color/textUnChecked"         //没有选中的文字颜色在HomepageFragment中的代码是:


public class HomepageFragment extends Fragment {    private ViewPager mViewPager;    private TabLayout mTabLayout;    private List<Fragment>mFragments;    private List<String>mTitles;    private HomepageAdapter mAdapter;     @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        View view=inflater.inflate(R.layout.fragment_homepage, container, false);        initView(view);        initData(view);        setData();        return view;    }     private void setData() {        mViewPager.setAdapter(mAdapter);        //设置Viewpager和Tablayout进行联动        mTabLayout.setupWithViewPager(mViewPager);//        //将标题设置可以左右摇动而不是移动//        mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);//        //设置预加载页数//        mViewPager.setOffscreenPageLimit(3);     }     private void initData(View view) {        //初始化导航标题,如果是title在json数据中,在初始化的时候可以使用异步任务加载的形式添加        mTitles=new ArrayList<>();        mTitles.add("热门");        mTitles.add("分类");        mTitles.add("榜单");        //初始化Fragment        mFragments=new ArrayList<>();        for (int i = 0; i <mTitles.size() ; i++) {            if(i==0){                mFragments.add(new HotFragment());            }else if(i==1){                mFragments.add(new ClassifyFragment());            }else if(i==2){                mFragments.add(new ListingFragment());            }        }        //getSupportFragmentManager()是Activity嵌套fragment时使用        //getChildFragmentManager()是Fragment嵌套Fragment时使用        mAdapter=new HomepageAdapter(getChildFragmentManager(),mFragments,mTitles);        mAdapter.notifyDataSetChanged();    }    private void initView(View view) {         mViewPager= (ViewPager) view.findViewById(R.id.vp_homepage_show);        mTabLayout= (TabLayout) view.findViewById(R.id.tl_homepage_navigation);    }}用到的Viewpager的Adapter代码是:


public class HomepageAdapter extends FragmentPagerAdapter {    private List<Fragment> mFragments;    private List<String> mTitles;     public HomepageAdapter(FragmentManager fm, List<Fragment> framents, List<String> titles) {        super(fm);        mFragments = framents;        mTitles = titles;    }     @Override    public Fragment getItem(int position) {        return mFragments.get(position);    }     @Override    public int getCount() {        return mFragments == null ? 0 : mFragments.size();    }     @Override    public CharSequence getPageTitle(int position) {        return mTitles.get(position);    }}最后所实现的效果如下所示:

      
二、使用Tablayout+Fragment实现底部导航
 注意:之后三种实现方式不再实现顶部导航,只实现底部导航,而在第二种方式中将详细介绍Tablyout的用法及属性。
        1,首先我们先总结一下Tablayout的基本使用(和顶部导航不同的方式实现)
第一种使用先看布局文件:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.linktestproject.TablayoutActivity">    <android.support.design.widget.TabLayout        android:id="@+id/tl_tablayout_navigation"        android:layout_width="match_parent"        android:layout_height="wrap_content"        >    </android.support.design.widget.TabLayout></android.support.constraint.ConstraintLayout>在代码中:

        mTabLayout.addTab(mTabLayout.newTab().setText("Title1"));        mTabLayout.addTab(mTabLayout.newTab().setText("Title2"));        mTabLayout.addTab(mTabLayout.newTab().setText("Title3"));        mTabLayout.addTab(mTabLayout.newTab().setText("Title4"));第二种使用方式(布局):


<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.linktestproject.TablayoutActivity">    <android.support.design.widget.TabLayout        android:id="@+id/tl_tablayout_navigation"        android:layout_width="match_parent"        android:layout_height="wrap_content"        >        <android.support.design.widget.TabItem            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Title1"/>        <android.support.design.widget.TabItem            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Title2"/>        <android.support.design.widget.TabItem            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Title3"/>        <android.support.design.widget.TabItem            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="Title4"/>    </android.support.design.widget.TabLayout></android.support.constraint.ConstraintLayout>二种方式实现的结果相同,如下图所示:

      
下边我们总结一下Tablayout的属性用法:


app:tabSelectedTextColor="  "  //改变选中字体的颜色


app:tabTextColor="   "  //改变未选中字体的颜色


app:tabIndicatorColor="   "   //改变指示器下标的颜色

           app:tabBackground="  "    //改变整个TabLayout的颜色

           app:tabTextAppearance="  "  //改变Tablayout的内部字体大小
   app:tabPadding="xxdp"  //内部子控件的Padding值
   app:paddingEnd="xxdp"  //设置整个Tablayout的Padding值
   app:paddingStart="xxdp"

   app:tabMaxWidth="xxdp"  //设置最小和最大的tab宽度
   app:tabMinWidth="xxdp"
   app:tabContentStart="xxdp" //设置Tablayout开始位置的偏移量
   tabLayout.addTab(tabLayout.newTab().setText("Tab 1").setIcon(R.mipmap.ic_launcher));//为Tablayout添加图片
        

       app:tabMode=“scrollable”  //这个属性用于tab比较多的情况下,实现的结果如下图:
      
  app:tabIndicatorHeight="  "//改变指示器下标的高度
 app:tabIndicatorHeight="0dp"//当设置为0时就会去掉指示器下标
     
    2,通过Tablayout+Fragment实现底部导航
首先布局文件很简单:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.linktestproject.TablayoutActivity">    <android.support.v4.view.ViewPager        android:id="@+id/vp_tablayout_show"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        ></android.support.v4.view.ViewPager>    <android.support.design.widget.TabLayout        android:id="@+id/tl_tablayout_navigation"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        style="@style/CustomTablayout"        >    </android.support.design.widget.TabLayout></LinearLayout>  给Tablayout设置style样式:


<style name="CustomTablayout" parent="Widget.Design.TabLayout">        <item name="tabIndicatorHeight">0dp</item>        <item name="tabSelectedTextColor">@color/textChecked</item>        <item name="tabTextColor">@color/textUnChecked</item>    </style>切换页面使用了ViewPager和Fragment,所以我们的适配器Adapter的内容:


public class TablayoutAdapter extends FragmentPagerAdapter {    private List<Fragment>mFragments;    private List<String>mTitles;    public TablayoutAdapter(FragmentManager fm, List<Fragment>mFragments, List<String>mTitles) {        super(fm);        this.mFragments=mFragments;        this.mTitles=mTitles;    }     @Override    public Fragment getItem(int position) {        return mFragments.get(position);    }     @Override    public int getCount() {        return mFragments==null?0:mFragments.size();    }     @Override    public CharSequence getPageTitle(int position) {        return mTitles.get(position);    }}最后是TablayoutActivity中的代码:


public class TablayoutActivity extends AppCompatActivity {     private TabLayout mTabLayout;    private ViewPager mViewPager;    private List<Fragment>mFragments;    private TablayoutAdapter mAdapter;    private List<String>mTitles;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_tablayout);        getSupportActionBar().hide();        initView();        initData();        setData();        setListener();    }     private void setListener() {     }     private void setData() {        mViewPager.setAdapter(mAdapter);        mTabLayout.setupWithViewPager(mViewPager);         for (int i = 0; i <mTabLayout.getTabCount() ; i++) {            TabLayout.Tab tab=mTabLayout.getTabAt(i);            Drawable drawable=null;            switch(i){                case 0:                    //图片资源我们同样要使用选择器,选择器我们不能使用state_checked属性,而应该使用state_selected属性                    drawable=getResources().getDrawable(R.drawable.hometablayout);                break;                case 1:                    drawable=getResources().getDrawable(R.drawable.subtablayout);                    break;                case 2:                    drawable=getResources().getDrawable(R.drawable.findtablayout);                    break;                case 3:                    drawable=getResources().getDrawable(R.drawable.minetablayout);                    break;            }                tab.setIcon(drawable);        }     }     private void initData() {        mTitles=new ArrayList<>();        mTitles.add("首页");        mTitles.add("订阅");        mTitles.add("发现");        mTitles.add("我的");        mFragments=new ArrayList<>();        for (int i = 0; i <mTitles.size(); i++) {            if(i==0){                mFragments.add(new HomepageFragment());            }else if(i==1){                mFragments.add(new SubscriptionFragment());            }else if(i==2){                mFragments.add(new FindFragment());            }else  if(i==3){                mFragments.add(new MineFragment());            }        }         mAdapter=new TablayoutAdapter(getSupportFragmentManager(),mFragments,mTitles);         mAdapter.notifyDataSetChanged();     }     private void initView() {        mTabLayout= (TabLayout) findViewById(R.id.tl_tablayout_navigation);        mViewPager= (ViewPager) findViewById(R.id.vp_tablayout_show);    }}

drawable=getResources().getDrawable(R.drawable.hometablayout);//这是一个已经过时的方法,
//现在是最新的方法是传入两个参数,但需要的最低版本有限制(Call requires API level 21 (current min is 15)):drawable=getResources().getDrawable(R.drawable.hometablayout,null);所以自己根据需要自己选择

上边注释的图片选择器要根据控件选择对应的属性,选择器内容如下:

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:state_selected="true" android:drawable="@mipmap/tab4_down"></item>    <item android:state_selected="false" android:drawable="@mipmap/tab4"></item></selector>以上就是Tablayout+ViewPager+Fragment实现底部导航的所有内容,实现的结果如下图所示:
    
       本来准备四种方式实现底部导航,但篇幅较大所以把下边两种方式写到下一遍博客中,我在源码中添加各个Fragment的生命周期方法Log,可以自己运行比较这几种实现方式。从我自己的开发经历以及Fragment的生命周期的比较,我推荐使用反射机制实现底部导航,并且反射也是你进阶需要掌握的一个知识点。
     源码下载地址(前两种方式):http://download.csdn.net/detail/huohao_blogs/9851738
     另两种实现博客地址:http://blog.csdn.net/huohao_blogs/article/details/72725391
     四种实现方式源码地址:http://download.csdn.net/detail/huohao_blogs/9852863
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值