App主界面Tab实现方法

Android 程序中实现Tab类型界面很常见,所以想在这里总结一下,实现tab类型界面的几种方式,供大家参考。
一、TabActivity + TabWidget + TabHost.
实现TAB类型界面,首先想到的就是这种方式。但是在API level 13之后官方就不建议使用它了。

二、ViewPager + PageAdapter

目前最常见的tab界面就是使用viewpager来实现了。
先来说一下viewpager的一般使用步骤:

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

  2. 在代码中设置viewpager适配器,该类继承与pagerAdapter或它的子类。必须实现以下四个方法:
    (1)getCount()
    (2)instantiateItem()
    (3)destroyItem()
    (4)isViewFromObject()

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

  4. 设置监听事件(setOnPageChangeListener)
    下面看一下这种方式的效果图:


    App主界面Tab实现方法_第1张图片

    主要的功能代码如下:

    private void init() {  
      viewPager = (ViewPager) findViewById(R.id.first_vp);  
      LayoutInflater inflater = LayoutInflater.from(this);  
      View view1 = inflater.inflate(R.layout.first_layout1, null);  
      View view2 = inflater.inflate(R.layout.first_layout2, null);  
      View view3 = inflater.inflate(R.layout.first_layout3, null);  
      list.add(view1);  
      list.add(view2);  
      list.add(view3);  
    
    viewPager.setAdapter(pagerAdapter);  
    viewPager.setOnPageChangeListener(new OnPageChangeListener() {  
       @Override  
       public void onPageSelected(int arg0) {  
           setDots(arg0);  
       }  
    
       @Override  
       public void onPageScrolled(int arg0, float arg1, int arg2) {  
       }  
    
       @Override  
       public void onPageScrollStateChanged(int arg0) {  
       }  
    });  
    }  
    
     private PagerAdapter pagerAdapter = new PagerAdapter() {  
      //官方建议这么写  
      @Override  
      public boolean isViewFromObject(View arg0, Object arg1) {  
       return arg0 == arg1;  
    }  
     //返回一共有多少个界面  
     @Override  
    public int getCount() {  
       return list.size();  
    }  
    
      @Override  
      public Object instantiateItem(ViewGroup container, int position) {  
       container.addView(list.get(position));  
       return list.get(position);  
     }  
       //销毁一个item  
     @Override  
    public void destroyItem(ViewGroup container, int position, Object object) {  
       container.removeView(list.get(position));  
    }  
    };  
    
适配器中必须要实现以上的四个方法。

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


/** 
 * 初始化底部的点 
 */  
private void initDots() {  
    pointLayout = (LinearLayout) findViewById(R.id.point_layout);  
    dots = new ImageView[list.size()];  
    for (int i = 0; i < list.size(); i++) {  
        dots[i] = (ImageView) pointLayout.getChildAt(i);  
    }  
    currentIndex = 0;  
    dots[currentIndex].setBackgroundResource(R.drawable.dian_down);  
}  

/** 
 * 当滚动的时候更换点的背景图 
 */  
private void setDots(int position) {  
    if (position < 0 || position > list.size() - 1  
            || currentIndex == position) {  
        return;  
    }  
    dots[position].setBackgroundResource(R.drawable.dian_down);  
    dots[currentIndex].setBackgroundResource(R.drawable.dian);  
    currentIndex = position;  
}  

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

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

// 三个选项卡  
private LinearLayout tab1Layout, tab2Layout, tab3Layout;  
// 默认选中第一个tab  
private int index = 1;  
// fragment管理类  
private FragmentManager fragmentManager;  
// 三个fragment  
private Fragment tab1Fragment, tab2Fragment, tab3Fragment;  

@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_second);  
    fragmentManager = getSupportFragmentManager();  
    init();  
}  

/** 
 * 初始化控件 
 */  
private void init() {  
    tab1Layout = (LinearLayout) findViewById(R.id.tab1_layout);  
    tab2Layout = (LinearLayout) findViewById(R.id.tab2_layout);  
    tab3Layout = (LinearLayout) findViewById(R.id.tab3_layout);  

    tab1Layout.setOnClickListener(this);  
    tab2Layout.setOnClickListener(this);  
    tab3Layout.setOnClickListener(this);  
    //  
    setDefaultFragment();  
}  

/** 
 * 设置默认显示的fragment 
 */  
private void setDefaultFragment() {  
    FragmentTransaction transaction = fragmentManager.beginTransaction();  
    tab1Fragment = new Tab1Fragment();  
    transaction.replace(R.id.content_layout, tab1Fragment);  
    transaction.commit();  
}  

/** 
 *切换fragment 
 * @param newFragment 
 */  
private void replaceFragment(Fragment newFragment) {  
    FragmentTransaction transaction = fragmentManager.beginTransaction();  
    if (!newFragment.isAdded()) {  
        transaction.replace(R.id.content_layout, newFragment);  
        transaction.commit();  
    } else {  
        transaction.show(newFragment);  
    }  
}  

/** 
 * 改变现象卡的选中状态 
 */  
private void clearStatus() {  
    if (index == 1) {  
        tab1Layout.setBackgroundColor(getResources().getColor(R.color.tab));  
    } else if (index == 2) {  
        tab2Layout.setBackgroundColor(getResources().getColor(R.color.tab));  
    } else if (index == 3) {  
        tab3Layout.setBackgroundColor(getResources().getColor(R.color.tab));  
    }  
}  

@Override  
public void onClick(View v) {  
    clearStatus();  
    switch (v.getId()) {  
    case R.id.tab1_layout:  
        if (tab1Fragment == null) {  
            tab1Fragment = new Tab1Fragment();  
        }  
        replaceFragment(tab1Fragment);  
        tab1Layout.setBackgroundColor(getResources().getColor(  
                R.color.tab_down));  
        index = 1;  
        break;  
    case R.id.tab2_layout:  
        if (tab2Fragment == null) {  
            tab2Fragment = new Tab2Fragment();  
        }  
        replaceFragment(tab2Fragment);  
        tab2Layout.setBackgroundColor(getResources().getColor(  
                R.color.tab_down));  
        index = 2;  
        break;  
    case R.id.tab3_layout:  
        if (tab3Fragment == null) {  
            tab3Fragment = new Tab3Fragment();  
        }  
        replaceFragment(tab3Fragment);  
        tab3Layout.setBackgroundColor(getResources().getColor(  
                R.color.tab_down));  
        index = 3;  
        break;  
    }  
}  

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


App主界面Tab实现方法_第2张图片

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

public class FragmentAdapter extends FragmentPagerAdapter {  
private ArrayList list;  
public FragmentAdapter(FragmentManager fm, ArrayList list) {  
    super(fm);  
    this.list = list;  
}  
@Override  
public Fragment getItem(int arg0) {  
    return list.get(arg0);  
}  
@Override  
public int getCount() {  
    return list.size();  
}  
}  

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

/** 
 * 初始化viewpager 
 */  
private void initViewPager() {  
    viewPager = (ViewPager) findViewById(R.id.third_vp);  
    fragmentsList = new ArrayList<>();  
    Fragment fragment = new Tab1Fragment();  
    fragmentsList.add(fragment);  
    fragment = new Tab2Fragment();  
    fragmentsList.add(fragment);  
    fragment = new Tab3Fragment();  
    fragmentsList.add(fragment);  

    viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(),  
            fragmentsList));  
    viewPager.setCurrentItem(0);  
    viewPager.setOnPageChangeListener(this);  
}  

对button添加点击事件。

  @Override  
 public void onClick(View v) {  
    switch (v.getId()) {  
    case R.id.tab1_tv:  
        viewPager.setCurrentItem(0);  
        break;  
    case R.id.tab2_tv:  
        viewPager.setCurrentItem(1);  
        break;  
    case R.id.tab3_tv:  
        viewPager.setCurrentItem(2);  
        break;  
    }  
}  

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

 @Override  
public void onPageScrolled(int position, float positionOffset,  
        int positionOffsetPixels) {  
    offset = (screen1_3 - cursorImg.getLayoutParams().width) / 2;  
    Log.d("111", position + "--" + positionOffset + "--"  
            + positionOffsetPixels);  
    final float scale = getResources().getDisplayMetrics().density;  
    if (position == 0) {// 0<->1  
        lp.leftMargin = (int) (positionOffsetPixels / 3) + offset;  
    } else if (position == 1) {// 1<->2  
        lp.leftMargin = (int) (positionOffsetPixels / 3) + screen1_3 +offset;  
    }  
    cursorImg.setLayoutParams(lp);  
    currentIndex = position;  
}  

onPageScrolled中的三个参数比较重要。第一个参数是position。它的含义是表示当前显示的界面中的第一个界面。意思就是的当滑动的时候,有可能出现两个界面,position指的是左边的界面。第二个参数是positionOffset指的是偏移量的比例,取值范围是[0, 1)。第三个参数是positionOffsetPixels是指偏移的像素值。后两个参数都相对页面(一个page)来说的。
我之前有看到过设置指示器的时候用的前两个参数的,我也试了一下,OK的。不过感觉比较复杂,看了一下官方api,用第三个参数更简单。关键就是理解第一个参数position。用这种方法我只在代码里有两个判断就可以完成了。
效果图如下:


App主界面Tab实现方法_第3张图片

五、Viewpager + PagerTitleStrip / PagerTabStrip
这种方式没有上一种效果好看,而且标题变动。不在详细介绍。

六、Viewpager + TabLayout
TabLayout 是官方的,最好的是它可以兼容到2.2以上版本,包括2.2。很简单。

  

  


  
  

这里面没有什么特别的,就是添加了一个TabLayout和Viewpager作为上下的布局。其中

app:tabIndicatorColor="@color/white"                 // 下方滚动的下划线颜色  
app:tabSelectedTextColor="@color/gray"               // tab被选中后,文字的颜色  
app:tabTextColor="@color/white"                      // tab默认的文字颜色  

因为这里面我每个栏目下,都会有一些列表,所以采用list的方式,在里面切换layout不太适合,所以我采用了List来直接加载多个fragment

public class TabAdapter extends FragmentPagerAdapter {  

private List list_fragment;                         //fragment列表  
private List list_Title;                              //tab名的列表  



public TabAdapter(FragmentManager fm,List list_fragment,List list_Title) {  
    super(fm);  
    this.list_fragment = list_fragment;  
    this.list_Title = list_Title;  
}  

@Override  
public Fragment getItem(int position) {  
    return list_fragment.get(position);  
}  

@Override  
public int getCount() {  
    return list_Title.size();  
}  

//此方法用来显示tab上的名字  
@Override  
public CharSequence getPageTitle(int position) {  

    return list_Title.get(position % list_Title.size());  
}  
}  

创建Fragment

public class PageFragment extends Fragment {

public static final String ARG_PAGE = "ARG_PAGE";
private int mPage;

public static PageFragment newInstance(int page) {
    Bundle args = new Bundle();
    args.putInt(ARG_PAGE, page);
    PageFragment pageFragment = new PageFragment();
    pageFragment.setArguments(args);
    return pageFragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mPage = getArguments().getInt(ARG_PAGE);
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_page, container, false);
    TextView textView = (TextView) view;
    textView.setText("Fragment #" + mPage);
    return view;
}
}

使用

public class TabFragment extends Fragment {  

private TabLayout tab_FindFragment_title;                            //定义TabLayout  
private ViewPager vp_FindFragment_pager;                             //定义viewPager  
private FragmentPagerAdapter fAdapter;                               //定义adapter  

private List list_fragment;                                //定义要装fragment的列表  
private List list_title;                                     //tab名称列表  


@Override  
public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                         Bundle savedInstanceState) {  
    View view = inflater.inflate(R.layout.fragment_find, container, false);  

    initControls(view);  

    return view;  
}  

/** 
 * 初始化各控件 
 * @param view 
 */  
private void initControls(View view) {  

    tab_FindFragment_title = (TabLayout)view.findViewById(R.id.tab_FindFragment_title);  
    vp_FindFragment_pager = (ViewPager)view.findViewById(R.id.vp_FindFragment_pager);  


    //将fragment装进列表中  
    list_fragment = new ArrayList<>();  
    list_fragment.add(new PageFragment.newInstance(1));  
    list_fragment.add(new PageFragment.newInstance(2));  
    list_fragment.add(new PageFragment.newInstance(3));  

    //将名称加载tab名字列表,正常情况下,我们应该在values/arrays.xml中进行定义然后调用  
    list_title = new ArrayList<>();  
    list_title.add("tab1");  
    list_title.add("tab2");  
    list_title.add("tab3");  
  

    //设置TabLayout的模式  
    tab_FindFragment_title.setTabMode(TabLayout.MODE_FIXED);  
    //为TabLayout添加tab名称  
    tab_FindFragment_title.addTab(tab_FindFragment_title.newTab().setText(list_title.get(0)));  
    tab_FindFragment_title.addTab(tab_FindFragment_title.newTab().setText(list_title.get(1)));  
    tab_FindFragment_title.addTab(tab_FindFragment_title.newTab().setText(list_title.get(2)));  


    fAdapter = new TabAdapter(getActivity().getSupportFragmentManager(),list_fragment,list_title);  

    //viewpager加载adapter  
    vp_FindFragment_pager.setAdapter(fAdapter);  
    //tab_FindFragment_title.setViewPager(vp_FindFragment_pager);  
    //TabLayout加载viewpager  
    tab_FindFragment_title.setupWithViewPager(vp_FindFragment_pager);  
    //tab_FindFragment_title.set  
}  
}  

七、TabPageIndicator/PagerSlidingTabStrip+ViewPager+FragmentPagerAdapter
TabPageIndicator 和 PagerSlidingTabStrip很像,不过有点过时了,不在详细介绍。
八、FlycoTabLayout
这个是我见过的最好的,大家可以点击看一下, 不在详细介绍。

你可能感兴趣的:(App主界面Tab实现方法)