Android 程序中实现Tab类型界面很常见,本人在做项目的时候也经常用到,所以想在这里总结一下,实现tab类型界面的几种方式,供大家参考。如有不对之处,欢迎大家指正!

一、TabActivity + TabWidget + TabHost.

实现TAB类型界面,首先想到的就是这种方式。但是在API level 13之后官方就不建议使用它了。不过还是在这里简单说一下它的使用吧。

使用它的关键就是布局文件了。需要在布局中添
加<TabHost>、<TabWidget>、<FrameLayout>这三个控件,id分别是系统提供
的:@android:id/tabhost 、@android:id/tabs 、@android:id/tabcontent 。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <TabHost
  7. android:id="@android:id/tabhost"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent" >
  10. <RelativeLayout
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent"
  13. android:orientation="vertical" >
  14. <!-- 可以指定tabwidget的位置    android:layout_alignParentBottom="true" -->
  15. <TabWidget
  16. android:id="@android:id/tabs"
  17. android:layout_width="match_parent"
  18. android:layout_height="wrap_content"
  19. android:layout_alignParentBottom="false" >
  20. </TabWidget>
  21. <FrameLayout
  22. android:id="@android:id/tabcontent"
  23. android:layout_width="match_parent"
  24. android:layout_height="match_parent"
  25. android:layout_below="@android:id/tabs" >
  26. <LinearLayout
  27. android:id="@+id/tab1"
  28. android:layout_width="match_parent"
  29. android:layout_height="match_parent"
  30. android:background="#DEB887"
  31. android:orientation="vertical" >
  32. </LinearLayout>
  33. <LinearLayout
  34. android:id="@+id/tab2"
  35. android:layout_width="match_parent"
  36. android:layout_height="match_parent"
  37. android:background="#BCEE68"
  38. android:orientation="vertical" >
  39. </LinearLayout>
  40. <LinearLayout
  41. android:id="@+id/tab3"
  42. android:layout_width="match_parent"
  43. android:layout_height="match_parent"
  44. android:background="#7D9EC0"
  45. android:orientation="vertical" >
  46. </LinearLayout>
  47. </FrameLayout>
  48. </RelativeLayout>
  49. </TabHost>
  50. </LinearLayout>

一个linearlayout对应一个tab页面的布局。

  1. tabHost = getTabHost();
  2. tabHost.addTab(tabHost
  3. .newTabSpec("111")
  4. .setIndicator("", getResources().getDrawable(R.drawable.wuyong))
  5. .setContent(R.id.tab1));
  6. tabHost.addTab(tabHost
  7. .newTabSpec("222")
  8. .setIndicator("",
  9. getResources().getDrawable(R.drawable.gongsunsheng))
  10. .setContent(R.id.tab2));
  11. tabHost.addTab(tabHost.newTabSpec("333")
  12. .setIndicator("", getResources().getDrawable(R.drawable.likui))
  13. .setContent(R.id.tab3));
  14. tabHost.setBackgroundColor(Color.argb(150, 22, 70, 150));
  15. tabHost.setCurrentTab(0);
  16. tabHost.setOnTabChangedListener(new OnTabChangeListener() {
  17. @Override
  18. public void onTabChanged(String tabId) {
  19. Toast.makeText(FourthActivity.this, tabId, Toast.LENGTH_SHORT)
  20. .show();
  21. }
  22. });

二、ViewPager + PageAdapter

目前最常见的tab界面就是使用viewpager来实现了。

先来说一下viewpager的一般使用步骤:

1. 在布局文件中添加viewpager控件

2. 在代码中设置viewpager适配器,该类继承与pagerAdapter或它的子类。必须实现以下四个方法:

(1)getCount()

(2)instantiateItem()

(3)destroyItem()

(4)isViewFromObject()

3. 初始化viewpager控件,设置监听器

4. 设置监听事件(setOnPageChangeListener)

下面看一下这种方式的效果图:

主要的功能代码如下:

  1. private void init() {
  2. viewPager = (ViewPager) findViewById(R.id.first_vp);
  3. LayoutInflater inflater = LayoutInflater.from(this);
  4. View view1 = inflater.inflate(R.layout.first_layout1, null);
  5. View view2 = inflater.inflate(R.layout.first_layout2, null);
  6. View view3 = inflater.inflate(R.layout.first_layout3, null);
  7. list.add(view1);
  8. list.add(view2);
  9. list.add(view3);
  10. viewPager.setAdapter(pagerAdapter);
  11. viewPager.setOnPageChangeListener(new OnPageChangeListener() {
  12. @Override
  13. public void onPageSelected(int arg0) {
  14. setDots(arg0);
  15. }
  16. @Override
  17. public void onPageScrolled(int arg0, float arg1, int arg2) {
  18. }
  19. @Override
  20. public void onPageScrollStateChanged(int arg0) {
  21. }
  22. });
  23. }
  1. private PagerAdapter pagerAdapter = new PagerAdapter() {
  1. <span style="white-space:pre">    </span>//官方建议这么写
  2. @Override
  3. public boolean isViewFromObject(View arg0, Object arg1) {
  4. return arg0 == arg1;
  5. }
  6. <span style="white-space:pre">     </span>//返回一共有多少个界面
  7. @Override
  8. public int getCount() {
  9. return list.size();
  10. }
  11. <span style="white-space:pre">        </span>//实例化一个item
  12. @Override
  13. public Object instantiateItem(ViewGroup container, int position) {
  14. container.addView(list.get(position));
  15. return list.get(position);
  16. }
  17. <span style="white-space:pre">       </span>//销毁一个item
  18. @Override
  19. public void destroyItem(ViewGroup container, int position, Object object) {
  20. container.removeView(list.get(position));
  21. }
  22. };

适配器中必须要实现以上的四个方法。

如果只有这几个页面,交互性肯定是不好的,所以需要添加“指示器”,用来标识当前的页面是哪一个!我在这里用点来实现。就像效果图显示的那样。

  1. /**
  2. * 初始化底部的点
  3. */
  4. private void initDots() {
  5. pointLayout = (LinearLayout) findViewById(R.id.point_layout);
  6. dots = new ImageView[list.size()];
  7. for (int i = 0; i < list.size(); i++) {
  8. dots[i] = (ImageView) pointLayout.getChildAt(i);
  9. }
  10. currentIndex = 0;
  11. dots[currentIndex].setBackgroundResource(R.drawable.dian_down);
  12. }
  13. /**
  14. * 当滚动的时候更换点的背景图
  15. */
  16. private void setDots(int position) {
  17. if (position < 0 || position > list.size() - 1
  18. || currentIndex == position) {
  19. return;
  20. }
  21. dots[position].setBackgroundResource(R.drawable.dian_down);
  22. dots[currentIndex].setBackgroundResource(R.drawable.dian);
  23. currentIndex = position;
  24. }

重点就是页面切换之后,点也要切换。这时候就用到了OnPageChangeListener中的onPageSelected(int arg0)这个方法了。

  1. @Override
  2. public void onPageSelected(int arg0) {
  3. setDots(arg0);
  4. }

三、Fragment + FragmentManager

fragment相信大家在项目中肯定都用过。这个方法主要就是利用fragmentManager对fragment的事务管理功能。

  1. // 三个选项卡
  2. private LinearLayout tab1Layout, tab2Layout, tab3Layout;
  3. // 默认选中第一个tab
  4. private int index = 1;
  5. // fragment管理类
  6. private FragmentManager fragmentManager;
  7. // 三个fragment
  8. private Fragment tab1Fragment, tab2Fragment, tab3Fragment;
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_second);
  13. fragmentManager = getSupportFragmentManager();
  14. init();
  15. }
  16. /**
  17. * 初始化控件
  18. */
  19. private void init() {
  20. tab1Layout = (LinearLayout) findViewById(R.id.tab1_layout);
  21. tab2Layout = (LinearLayout) findViewById(R.id.tab2_layout);
  22. tab3Layout = (LinearLayout) findViewById(R.id.tab3_layout);
  23. tab1Layout.setOnClickListener(this);
  24. tab2Layout.setOnClickListener(this);
  25. tab3Layout.setOnClickListener(this);
  26. //
  27. setDefaultFragment();
  28. }
  29. /**
  30. * 设置默认显示的fragment
  31. */
  32. private void setDefaultFragment() {
  33. FragmentTransaction transaction = fragmentManager.beginTransaction();
  34. tab1Fragment = new Tab1Fragment();
  35. transaction.replace(R.id.content_layout, tab1Fragment);
  36. transaction.commit();
  37. }
  38. /**
  39. *切换fragment
  40. * @param newFragment
  41. */
  42. private void replaceFragment(Fragment newFragment) {
  43. FragmentTransaction transaction = fragmentManager.beginTransaction();
  44. if (!newFragment.isAdded()) {
  45. transaction.replace(R.id.content_layout, newFragment);
  46. transaction.commit();
  47. } else {
  48. transaction.show(newFragment);
  49. }
  50. }
  51. /**
  52. * 改变现象卡的选中状态
  53. */
  54. private void clearStatus() {
  55. if (index == 1) {
  56. tab1Layout.setBackgroundColor(getResources().getColor(R.color.tab));
  57. } else if (index == 2) {
  58. tab2Layout.setBackgroundColor(getResources().getColor(R.color.tab));
  59. } else if (index == 3) {
  60. tab3Layout.setBackgroundColor(getResources().getColor(R.color.tab));
  61. }
  62. }
  63. @Override
  64. public void onClick(View v) {
  65. clearStatus();
  66. switch (v.getId()) {
  67. case R.id.tab1_layout:
  68. if (tab1Fragment == null) {
  69. tab1Fragment = new Tab1Fragment();
  70. }
  71. replaceFragment(tab1Fragment);
  72. tab1Layout.setBackgroundColor(getResources().getColor(
  73. R.color.tab_down));
  74. index = 1;
  75. break;
  76. case R.id.tab2_layout:
  77. if (tab2Fragment == null) {
  78. tab2Fragment = new Tab2Fragment();
  79. }
  80. replaceFragment(tab2Fragment);
  81. tab2Layout.setBackgroundColor(getResources().getColor(
  82. R.color.tab_down));
  83. index = 2;
  84. break;
  85. case R.id.tab3_layout:
  86. if (tab3Fragment == null) {
  87. tab3Fragment = new Tab3Fragment();
  88. }
  89. replaceFragment(tab3Fragment);
  90. tab3Layout.setBackgroundColor(getResources().getColor(
  91. R.color.tab_down));
  92. index = 3;
  93. break;
  94. }
  95. }

每一个fragment对应一个布局,点击不同的按钮来切换页面。效果如下图:

 

四、ViewPager + Fragment + FragmentPagerAdapter

如果想使用fragment的时候又想可以左右滑动,就可以使用这种方式。主要的部分就在viewpager的适配器。它的适配器继承FragmentPagerAdapter.

  1. package com.tab.view.demo3;
  2. import java.util.ArrayList;
  3. import android.support.v4.app.Fragment;
  4. import android.support.v4.app.FragmentManager;
  5. import android.support.v4.app.FragmentPagerAdapter;
  6. public class FragmentAdapter extends FragmentPagerAdapter {
  7. private ArrayList<Fragment> list;
  8. public FragmentAdapter(FragmentManager fm, ArrayList<Fragment> list) {
  9. super(fm);
  10. this.list = list;
  11. }
  12. @Override
  13. public Fragment getItem(int arg0) {
  14. return list.get(arg0);
  15. }
  16. @Override
  17. public int getCount() {
  18. return list.size();
  19. }
  20. }

需要传入FragmentManager对象和一个存放fragment的list对象。

  1. /**
  2. * 初始化viewpager
  3. */
  4. private void initViewPager() {
  5. viewPager = (ViewPager) findViewById(R.id.third_vp);
  6. fragmentsList = new ArrayList<>();
  7. Fragment fragment = new Tab1Fragment();
  8. fragmentsList.add(fragment);
  9. fragment = new Tab2Fragment();
  10. fragmentsList.add(fragment);
  11. fragment = new Tab3Fragment();
  12. fragmentsList.add(fragment);
  13. viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(),
  14. fragmentsList));
  15. viewPager.setCurrentItem(0);
  16. viewPager.setOnPageChangeListener(this);
  17. }

对button添加点击事件。

  1. @Override
  2. public void onClick(View v) {
  3. switch (v.getId()) {
  4. case R.id.tab1_tv:
  5. viewPager.setCurrentItem(0);
  6. break;
  7. case R.id.tab2_tv:
  8. viewPager.setCurrentItem(1);
  9. break;
  10. case R.id.tab3_tv:
  11. viewPager.setCurrentItem(2);
  12. break;
  13. }
  14. }


在布局文件中添加了一个imageview作为指示器。如果想第一种tab类型界面的实现方式那样在onPageSelected()方法中进行设置,效
果是只能当页面完全切换过来之后才能把指示器移动过去。要想实现滑动页面的时候同时移动指示器,就需要在onPageScrolled()方法中进行设
置。

  1. @Override
  2. public void onPageScrolled(int position, float positionOffset,
  3. int positionOffsetPixels) {
  4. offset = (screen1_3 - cursorImg.getLayoutParams().width) / 2;
  5. Log.d("111", position + "--" + positionOffset + "--"
  6. + positionOffsetPixels);
  7. final float scale = getResources().getDisplayMetrics().density;
  8. if (position == 0) {// 0<->1
  9. lp.leftMargin = (int) (positionOffsetPixels / 3) + offset;
  10. } else if (position == 1) {// 1<->2
  11. lp.leftMargin = (int) (positionOffsetPixels / 3) + screen1_3 +offset;
  12. }
  13. cursorImg.setLayoutParams(lp);
  14. currentIndex = position;
  15. }

onPageScrolled中的三个参数比较重要。第一个参数是position。它的含义是表示当前显示的界面中的第一个界面。意思就是的当滑动的时
候,有可能出现两个界面,position指的是左边的界面。第二个参数是positionOffset指的是偏移量的比例,取值范围是[0,
1)。第三个参数是positionOffsetPixels是指偏移的像素值。后两个参数都相对页面(一个page)来说的。

我之前有看到过设置指示器的时候用的前两个参数的,我也试了一下,OK的。不过感觉比较复杂,看了一下官方api,用第三个参数更简单。关键就是理解第一个参数position。用这种方法我只在代码里有两个判断就可以完成了。

效果图如下:

 

五、Viewpager + PagerTitleStrip / PagerTabStrip

这种方式没有上一种效果好看,而且标题变动。看一下效果图:

 

布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <android.support.v4.view.ViewPager
  7. android:id="@+id/fifth_vp"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="center" >
  11. <android.support.v4.view.PagerTabStrip
  12. android:id="@+id/fifth_strip"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_gravity="top"
  16. android:background="#7EC0EE"
  17. android:padding="10dip" />
  18. </android.support.v4.view.ViewPager>
  19. </LinearLayout>

先来说一下PagerTitleStrip和PagerTabStrip的区别:PagerTitleStrip没有指示器,只有标题,且标题没有响应事
件;而PagerTabStrip是带有指示器的,当然也有标题,具有相应事件。二者的实现只在布局文件中有区别,只需要把
android.support.v4.view.PagerTabStrip改成
android.support.v4.viewPagerTitleStrip即可。
    代码中需要注意的就是,在适配器中重写getPageTitle(int)方法来显示标题。

  1. PagerAdapter pagerAdapter = new PagerAdapter() {
  2. //此处省略其他的方法
  1. // 重写此方法即可显示标题
  2. @Override
  3. public CharSequence getPageTitle(int position) {
  4. return titleList.get(position);
  5. }
  6. ;

总结:

我目前所遇到的tab类型界面的实现方式就是这么多了,若果大家有其他的实现方式,请留言。如果我写的有误,请留言指正,共同进步!谢谢!

Demo下载地址:http://download.csdn.net/detail/crazy1235/8358671

Android UI 之 Tab类型界面总结的更多相关文章

  1. android ui篇 自己写界面

    对于一些较为简单的界面则自己进行写. 在这里就需要了解xml文件中一些基本的属性以及android手机的知识. 一.目前手机屏幕像素密度基本有5种情况.(以下像素密度简称密度) 密度 ldpi mdp ...

  2. Android UI学习 - Tab的学习和使用(转)

      本文是参考Android官方提供的sample里面的ApiDemos的学习总结.   TabActivity   首先Android里面有个名为TabActivity来给我们方便使用.其中有以下可 ...

  3. android Tab 类型切换界面

    实现方案:viewpager + fragment + FragmentPagerAdapter 效果图: 可以左右滑动切换选项卡,或者点击: 如果想使用fragment的时候又想可以左右滑动,就可以 ...

  4. Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977 Android如今实现Tab类型的界面方式越来越多,今天就把常见的 ...

  5. Android Tab类型主界面 Fragment+TabPageIndicator+ViewPager

    文章地址: Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager 1.使用ViewPager + PagerAdapter 每个页面的内容都 ...

  6. Android UI开发第三十九篇——Tab界面实现汇总及比较

    Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...

  7. 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面

    [Android UI设计与开发]第05期:引导界面(五)实现应用程序只启动一次引导界面 jingqing 发表于 2013-7-11 14:42:02 浏览(229501) 这篇文章算是对整个引导界 ...

  8. android ui界面设计参数讲解

    百度文库: http://wenku.baidu.com/link?url=s66Hw6byBEzmjL77doYL1YQN4Y_39F7MovaHKs5mVGrzTDOQCAmiM-1N_6Cdm- ...

  9. iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸

    iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸 iPhone界面尺寸 设备 分辨 ...

随机推荐

  1. AUTH过程

    INITIALIZE UPDATE: 在安全通道的显式发起期间,INITIALIZEUPDATE命令用于在卡和主机之间传送卡和会话数据.这个命令开始一个安全通道会话的发起. CPURESET() // ...

  2. 第三次作业,github的基本操作

    chengjiangtao@pc MINGW32 ~$ git config --global user.name "chengjiangtao" chengjiangtao@pc ...

  3. Node.js 学习(四)Node.js 回调函数

    Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都 ...

  4. OpenCms 集成外部Solr Server

    OpenCms默认是以内嵌的Solr作为全文搜索服务的,不过我们也可以配置一个独立的Solr搜索服务器 设置外部Solr Server 1. 从Solr 官方站点http://lucene.apach ...

  5. cygwin and its host machine

    Senario 本来我是想要修改下 machine name 在Ubuntu中的步骤是这样的 1 sudo hostname newMechineName 2 sudo vi /etc/hostnam ...

  6. HDU 5763 Another Meaning KMP+DP

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 Another Meaning Time Limit: 2000/1000 MS (Java/ ...

  7. ionice

    ionice – 获取或设置程序的IO调度与优先级. 命令格式: ionice [[-c class] [-n classdata] [-t]] -p PID [PID]… ionice [-c cl ...

  8. 02.JSP的3个编译指令

    本章介绍JSP的3个编译指令,在JSP中常见的编译指令有如下3个:         1.page:用于针对当前页面的指令.         2.include:用于指定包含另一个页面.         ...

  9. 【BZOJ】【1030】【JSOI2007】文本生成器

    AC自动机/DP Orz ZYF 玛雅快要省选了,赶紧复(xue)习(xi)一下AC自动机…… 其实在AC自动机上DP并没有当初想的那么复杂……就是把DP的转移关系换成了AC自动机上的边而已(不过这题 ...

  10. <string>和<string.h>的区别

    转自:http://blog.csdn.net/houjixin/article/details/8648969 在C++开发过程中经常会遇到两个比较容易混淆的头文件引用#include<str ...