android-多种方式实现主界面的Tab

当筵意气临九霄,星离雨散不终朝。这篇文章主要讲述android-多种方式实现主界面的Tab相关的知识,希望能为你提供帮助。
本人水平有限,文章中如果出现什么不正确或者模糊的地方,还请各位小伙伴留下评论,多多指教 : )

  • 前言
  • 使用Fragment实现
    • 思路
    • 效果
    • 具体讲解
      • 底部布局
      • 顶部布局
      • Fragment的布局
      • Java控制代码
  • 使用ViewPager实现
    • 思路
    • 效果
    • 具体实现
  • 使用ViewPagerFragmentPagerAdapter方法实现
    • 思路
    • 效果
    • 补充
    • 具体代码
  • 使用框架

前言这篇文章主要介绍多种方式实现主界面的tab,包括:
(1)使用Fragment实现
(2)使用ViewPage实现
(3)使用ViewPage+FragmentPageAdapter
(4)使用框架实现
在线的视频课程来自慕课网——多种多样的App主界面Tab实现方法。觉得文字不好理解的小伙伴可以去看视频,然后再回头自己敲一遍。
使用Fragment实现比较常规的使用方法,需要大家对Fragment有基本了解,这里推荐hongyang大神的几篇博文:
Android Fragment 真正的完全解析(上)
Android Fragment 真正的完全解析(下)
相信各位看完之后对Fragment就能有一个比较清楚的了解。
思路这种方式实现的思路比较简单:
1、首先在主布局中加入FragmentLayout
2、然后在java代码中监听底部的按钮,当点击时,只需让FragmentLayout加载相应的Fragment即可
android-多种方式实现主界面的Tab

文章图片

效果
android-多种方式实现主界面的Tab

文章图片

可以看到,如果单纯地使用Fragment,实际上是不能实现左右滑动的效果,页面的切换,只能靠点击底部的Button来实现。
具体讲解底部布局
首先是底部的一个布局文件bottom.xml
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="65dp" android:background="@drawable/bottom_bar"> < LinearLayout android:id="@+id/id_tab_weixin" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> < ImageButton android:id="@+id/id_tab_weixin_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="https://www.songbingjia.com/android/@drawable/tab_weixin_pressed" android:background="#0000"/> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#fff" android:text="微信"/> < /LinearLayout> < LinearLayout android:id="@+id/id_tab_frd" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> < ImageButton android:id="@+id/id_tab_frd_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="https://www.songbingjia.com/android/@drawable/tab_find_frd_normal" android:background="#0000"/> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#fff" android:text="朋友"/> < /LinearLayout> < LinearLayout android:id="@+id/id_tab_address" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> < ImageButton android:id="@+id/id_tab_address_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="https://www.songbingjia.com/android/@drawable/tab_address_normal" android:background="#0000"/> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#fff" android:text="通讯录"/> < /LinearLayout> < LinearLayout android:id="@+id/id_tab_setting" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> < ImageButton android:id="@+id/id_tab_setting_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="https://www.songbingjia.com/android/@drawable/tab_settings_normal" android:background="#0000"/> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#fff" android:text="设置"/> < /LinearLayout> < /LinearLayout>

简单的线性布局,放置我们的按钮。
android-多种方式实现主界面的Tab

文章图片

这个布局在后面的栗子中也会使用。
顶部布局
接下来是一个顶部的title
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="45dp" android:gravity="center" android:background="@drawable/title_bar"> < TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="微信" android:textColor="#ffffff" android:textSize="20sp" android:textStyle="bold" android:layout_gravity="center"/> < /LinearLayout>

就一个TextView。
Fragment的布局
android-多种方式实现主界面的Tab

文章图片

【android-多种方式实现主界面的Tab】为了简单起见,这里面的布局只放置一个TextView
Java控制代码
TestActivity2
public class TestActivity2 extends Activity implements View.OnClickListener { private LinearLayout mTabWeixin; private LinearLayout mTabFrd; private LinearLayout mTabAddress; private LinearLayout mTabSetting; //底部的按钮 private ImageButton mWeiXin; private ImageButton mFriend; private ImageButton mAddress; private ImageButton mSetting; //FragmentLayout要加载的四个Fragment private WeiXinFragment weiXinFragment; private FriendFragment friendFragment; private AddressFragment addressFragment; private SettingFragment settingFragment; //顶部的标题 private TextView tvTitle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.test_ac_2); initView(); initEvents(); setSelect(0); }private void initEvents() { mWeiXin.setOnClickListener(this); mFriend.setOnClickListener(this); mAddress.setOnClickListener(this); mSetting.setOnClickListener(this); }private void initView() { //初始化mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin); mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd); mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address); mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting); mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img); mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img); mAddress= (ImageButton) findViewById(R.id.id_tab_address_img); mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img); tvTitle= (TextView) findViewById(R.id.tv_title); }@Override public void onClick(View view) {switch (view.getId()){ case R.id.id_tab_weixin_img: setSelect(0); break; case R.id.id_tab_frd_img: setSelect(1); break; case R.id.id_tab_address_img: setSelect(2); break; case R.id.id_tab_setting_img: setSelect(3); break; }}private void hideFragment(FragmentTransaction fragmentTransaction) { if (weiXinFragment!=null){ fragmentTransaction.hide(weiXinFragment); } if (friendFragment!=null){ fragmentTransaction.hide(friendFragment); } if (addressFragment!=null){ fragmentTransaction.hide(addressFragment); } if (settingFragment!=null){ fragmentTransaction.hide(settingFragment); } }/* * 重置所有的图片,让其恢复到灰色状态 * */ private void resetImage() { mSetting.setImageResource(R.drawable.tab_settings_normal); mWeiXin.setImageResource(R.drawable.tab_weixin_normal); mAddress.setImageResource(R.drawable.tab_address_normal); mFriend.setImageResource(R.drawable.tab_find_frd_normal); }/* * 设置某个Fragment * */ private void setSelect(int i){ FragmentManager fm=getFragmentManager(); FragmentTransaction fragmentTransaction=fm.beginTransaction(); //重置图片状态 resetImage(); hideFragment(fragmentTransaction); switch (i){ case 0: //设置标题 tvTitle.setText("微信"); if (weiXinFragment==null){ //如果Fragment还没实例化,实例化,并在fragmentTransaction中添加 weiXinFragment=new WeiXinFragment(); fragmentTransaction.add(R.id.id_content,weiXinFragment); }else{ //如果已经实例化了,就显示 fragmentTransaction.show(weiXinFragment); } fragmentTransaction.commit(); //改变底部图标的状态 mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); break; case 1: tvTitle.setText("朋友"); if (friendFragment==null){ friendFragment=new FriendFragment(); fragmentTransaction.add(R.id.id_content,friendFragment); }else{ fragmentTransaction.show(friendFragment); }fragmentTransaction.commit(); mFriend.setImageResource(R.drawable.tab_find_frd_pressed); break; case 2: tvTitle.setText("通讯录"); if (addressFragment==null){ addressFragment=new AddressFragment(); fragmentTransaction.add(R.id.id_content,addressFragment); }else{ fragmentTransaction.show(addressFragment); } fragmentTransaction.commit(); mAddress.setImageResource(R.drawable.tab_address_pressed); break; case 3: tvTitle.setText("设置"); if (settingFragment==null){ settingFragment=new SettingFragment(); fragmentTransaction.add(R.id.id_content,settingFragment); }else{ fragmentTransaction.show(settingFragment); } fragmentTransaction.commit(); mSetting.setImageResource(R.drawable.tab_settings_pressed); break; }} }

代码逻辑很清楚,中间需要提醒的地方已经用注释表明,这个小栗子其实就是Fragment的常规使用,涉及到的内容也都是Fragment基础知识,需要各位小伙伴烂熟于心。
使用ViewPager实现思路在上一个栗子当中,我们使用的是FragmentLayout来作为填充Fragment的容器。当使用ViewPage,我们需要把布局文件中的Layout替换成ViewPager。这就要求开发者对ViewPager的使用有基本的了解。
效果
android-多种方式实现主界面的Tab

文章图片

可以看到使用了ViewPager之后不仅可以实现左右的滑动,而且还能通过底部的点击来实现页面切换的效果
具体实现首先是布局文件
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> < include layout="@layout/top"/> < android.support.v4.view.ViewPager android:id="@+id/id_viewpager" android:layout_width="match_parent" android:layout_weight="1" android:layout_height="0dp"> < /android.support.v4.view.ViewPager> < include layout="@layout/bottom"/> < /LinearLayout>

非常简单,就是把中间的FragmentLayout换成了ViewPager。
重点在于接下里的Java代码当中,里面涉及到了ViewPager的基本使用。
public class TestActivity1 extends Activity implements View.OnClickListener { private ViewPager viewPager; private PagerAdapter pagerAdapter; private List< View> mViews =new ArrayList< > (); private FragmentPagerAdapter fragmentPagerAdapter; private FragmentStatePagerAdapter fragmentStatePagerAdapter; private LinearLayout mTabWeixin; private LinearLayout mTabFrd; private LinearLayout mTabAddress; private LinearLayout mTabSetting; private ImageButton mWeiXin; private ImageButton mFriend; private ImageButton mAddress; private ImageButton mSetting; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.test_ac_1); initView(); initEvents(); }/* * 初始化事件 * */ private void initEvents() { mWeiXin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { viewPager.setCurrentItem(0); mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); } }); mSetting.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { viewPager.setCurrentItem(3); mSetting.setImageResource(R.drawable.tab_settings_pressed); } }); mAddress.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { viewPager.setCurrentItem(2); mAddress.setImageResource(R.drawable.tab_address_pressed); } }); mFriend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { viewPager.setCurrentItem(1); mFriend.setImageResource(R.drawable.tab_find_frd_pressed); } }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { int currentItem =viewPager.getCurrentItem(); resetImage(); switch (currentItem){ case 0: mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); break; case 1: mFriend.setImageResource(R.drawable.tab_find_frd_pressed); break; case 2: mAddress.setImageResource(R.drawable.tab_address_pressed); break; case 3: mSetting.setImageResource(R.drawable.tab_settings_pressed); break; } }@Override public void onPageSelected(int position) {}@Override public void onPageScrollStateChanged(int state) {} }); }private void initView() { //初始化 viewPager= (ViewPager) findViewById(R.id.id_viewpager); mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin); mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd); mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address); mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting); mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img); mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img); mAddress= (ImageButton) findViewById(R.id.id_tab_address_img); mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img); LayoutInflater mLayoutInfater=LayoutInflater.from(this); View view1=mLayoutInfater.inflate(R.layout.tab01,null); View view2=mLayoutInfater.inflate(R.layout.tab02,null); View view3=mLayoutInfater.inflate(R.layout.tab03,null); View view4=mLayoutInfater.inflate(R.layout.tab04,null); mViews.add(view1); mViews.add(view2); mViews.add(view3); mViews.add(view4); pagerAdapter=new PagerAdapter() {@Override public Object instantiateItem(ViewGroup container, int position) { View view=mViews.get(position); container.addView(view); return view; }@Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mViews.get(position)); }@Override public int getCount() { return mViews.size(); }@Override public boolean isViewFromObject(View view, Object object) { return view==object; } }; viewPager.setAdapter(pagerAdapter); }@Override public void onClick(View view) { Log.d("--tab--","tab click"); //重置所有的图片 resetImage(); switch (view.getId()){ case R.id.id_tab_weixin: viewPager.setCurrentItem(0); mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); Log.d("--tab--","tab weixin"); break; case R.id.id_tab_frd: viewPager.setCurrentItem(1); mFriend.setImageResource(R.drawable.tab_find_frd_pressed); Log.d("--tab--","tab friend"); break; case R.id.id_tab_address: viewPager.setCurrentItem(2); mAddress.setImageResource(R.drawable.tab_address_pressed); Log.d("--tab--","tab address"); break; case R.id.id_tab_setting: viewPager.setCurrentItem(3); mSetting.setImageResource(R.drawable.tab_settings_pressed); Log.d("--tab--","tab setting"); break; } }/* * 让所有的图片都变暗 * */ private void resetImage() { mSetting.setImageResource(R.drawable.tab_settings_normal); mWeiXin.setImageResource(R.drawable.tab_weixin_normal); mAddress.setImageResource(R.drawable.tab_address_normal); mFriend.setImageResource(R.drawable.tab_find_frd_normal); } }

使用ViewPager+FragmentPagerAdapter方法实现思路同ViewPager实现相同
效果同ViewPager实现相同
补充既然这种方式使用的思路和效果和直接使用ViewPager的相同,那么采用FragmenAdapter的方式来实现Tab页面切换有什么好处呢?
首先单纯使用ViewPager时,里面的View是通过LayoutInfater装载进去的,虽然也能够实现和和采用FragmentPagerAdapter一样的效果,但是如果这么做,必然所有的逻辑控制都放在MainActivity当中,对于后期代码的维护十分不利。
使用FragmentPagerAdapter的好处之一就是能够使得当前页面的逻辑处理仅有当前Fragment来承担,相当于把MainActivity里面的事件逻辑分派给了Fragment来处理。这个优点,其实在使用Fragment的时候也能体现出来。
所以说,如果仅仅是页面的展示(如图片轮播),直接使用ViewPager就好了,但如果ViewPager的每个页面中包含比较复杂的逻辑,就应该使用ViewPager+FragmentPagerAdapter的方式来完成Tab页面的切换。
具体代码xml与ViewPager实现的相同,不再重复。
Java代码:
public class TestActivity3 extends FragmentActivity implements View.OnClickListener { private ViewPager viewPager; private FragmentPagerAdapter mAdapter; private List< Fragment> fragments; private LinearLayout mTabWeixin; private LinearLayout mTabFrd; private LinearLayout mTabAddress; private LinearLayout mTabSetting; private ImageButton mWeiXin; private ImageButton mFriend; private ImageButton mAddress; private ImageButton mSetting; private int select; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.test_ac_3); initView(); initEvent(); }private void initEvent() { mWeiXin.setOnClickListener(this); mFriend.setOnClickListener(this); mAddress.setOnClickListener(this); mSetting.setOnClickListener(this); }private void initView() { //初始化 viewPager= (ViewPager) findViewById(R.id.id_viewpager3); mTabWeixin= (LinearLayout) findViewById(R.id.id_tab_weixin); mTabFrd= (LinearLayout) findViewById(R.id.id_tab_frd); mTabAddress= (LinearLayout) findViewById(R.id.id_tab_address); mTabSetting= (LinearLayout) findViewById(R.id.id_tab_setting); mWeiXin= (ImageButton) findViewById(R.id.id_tab_weixin_img); mFriend= (ImageButton) findViewById(R.id.id_tab_frd_img); mAddress= (ImageButton) findViewById(R.id.id_tab_address_img); mSetting= (ImageButton) findViewById(R.id.id_tab_setting_img); fragments=new ArrayList< > (); WeiXinFragment weiXinFragment=new WeiXinFragment(); FriendFragment friendFragment=new FriendFragment(); AddressFragment addressFragment=new AddressFragment(); SettingFragment settingFragment=new SettingFragment(); fragments.add(weiXinFragment); fragments.add(friendFragment); fragments.add(addressFragment); fragments.add(settingFragment); mAdapter=new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return fragments.get(position); }@Override public int getCount() { return fragments.size(); } }; viewPager.setAdapter(mAdapter); viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Override public void onPageSelected(int position) { resetImage(); switch (position){ case 0: mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); viewPager.setCurrentItem(0); break; case 1: mFriend.setImageResource(R.drawable.tab_find_frd_pressed); viewPager.setCurrentItem(1); break; case 2: mAddress.setImageResource(R.drawable.tab_address_pressed); viewPager.setCurrentItem(2); break; case 3: mSetting.setImageResource(R.drawable.tab_settings_pressed); viewPager.setCurrentItem(3); break; } }@Override public void onPageScrollStateChanged(int state) {} }); }@Override public void onClick(View view) { resetImage(); switch (view.getId()) { case R.id.id_tab_weixin_img: setSelect(0); break; case R.id.id_tab_frd_img: setSelect(1); break; case R.id.id_tab_address_img: setSelect(2); break; case R.id.id_tab_setting_img: setSelect(3); break; } }public void setSelect(int select) {switch (select){ case 0: mWeiXin.setImageResource(R.drawable.tab_weixin_pressed); viewPager.setCurrentItem(0); break; case 1: mFriend.setImageResource(R.drawable.tab_find_frd_pressed); viewPager.setCurrentItem(1); break; case 2: mAddress.setImageResource(R.drawable.tab_address_normal); viewPager.setCurrentItem(2); break; case 3: mSetting.setImageResource(R.drawable.tab_settings_pressed); viewPager.setCurrentItem(3); break; } }private void resetImage() { mSetting.setImageResource(R.drawable.tab_settings_normal); mWeiXin.setImageResource(R.drawable.tab_weixin_normal); mAddress.setImageResource(R.drawable.tab_address_normal); mFriend.setImageResource(R.drawable.tab_find_frd_normal); }}

使用框架如果每一次在开发的过程当中都去写一个这样的Tab页面,无疑耗时耗力,当然,对于初学者而言,这种“耗时耗力”能够帮助他们了解效果实现的基本实现原理。
在这里推荐给大家一款比较不错的ViewPager框架:
LuckyJayce/ViewPagerIndicator
里面的介绍比较详细,这里就不多讲了,对这个框架感兴趣的小伙伴可以去github上仔细研读一下~












    推荐阅读