App主界面Tab實(shí)現(xiàn)方法

Android 程序中實(shí)現(xiàn)Tab類(lèi)型界面很常見(jiàn),所以想在這里總結(jié)一下,實(shí)現(xiàn)tab類(lèi)型界面的幾種方式,供大家參考。
一、TabActivity + TabWidget + TabHost.
實(shí)現(xiàn)TAB類(lèi)型界面,首先想到的就是這種方式。但是在API level 13之后官方就不建議使用它了。

二、ViewPager + PageAdapter

目前最常見(jiàn)的tab界面就是使用viewpager來(lái)實(shí)現(xiàn)了。
先來(lái)說(shuō)一下viewpager的一般使用步驟:

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

  2. 在代碼中設(shè)置viewpager適配器,該類(lèi)繼承與pagerAdapter或它的子類(lèi)。必須實(shí)現(xiàn)以下四個(gè)方法:
    (1)getCount()
    (2)instantiateItem()
    (3)destroyItem()
    (4)isViewFromObject()

  3. 初始化viewpager控件,設(shè)置監(jiān)聽(tīng)器

  4. 設(shè)置監(jiān)聽(tīng)事件(setOnPageChangeListener)
    下面看一下這種方式的效果圖:



    主要的功能代碼如下:

    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() {  
      //官方建議這么寫(xiě)  
      @Override  
      public boolean isViewFromObject(View arg0, Object arg1) {  
       return arg0 == arg1;  
    }  
     //返回一共有多少個(gè)界面  
     @Override  
    public int getCount() {  
       return list.size();  
    }  
    
      @Override  
      public Object instantiateItem(ViewGroup container, int position) {  
       container.addView(list.get(position));  
       return list.get(position);  
     }  
       //銷(xiāo)毀一個(gè)item  
     @Override  
    public void destroyItem(ViewGroup container, int position, Object object) {  
       container.removeView(list.get(position));  
    }  
    };  
    
適配器中必須要實(shí)現(xiàn)以上的四個(gè)方法。

如果只有這幾個(gè)頁(yè)面,交互性肯定是不好的,所以需要添加“指示器”,用來(lái)標(biāo)識(shí)當(dāng)前的頁(yè)面是哪一個(gè)!我在這里用點(diǎn)來(lái)實(shí)現(xiàn)。就像效果圖顯示的那樣。


/** 
 * 初始化底部的點(diǎn) 
 */  
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);  
}  

/** 
 * 當(dāng)滾動(dòng)的時(shí)候更換點(diǎn)的背景圖 
 */  
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;  
}  

重點(diǎn)就是頁(yè)面切換之后,點(diǎn)也要切換。這時(shí)候就用到了OnPageChangeListener中的onPageSelected(int arg0)這個(gè)方法了。

三、Fragment + FragmentManager
fragment相信大家在項(xiàng)目中肯定都用過(guò)。這個(gè)方法主要就是利用fragmentManager對(duì)fragment的事務(wù)管理功能。

// 三個(gè)選項(xiàng)卡  
private LinearLayout tab1Layout, tab2Layout, tab3Layout;  
// 默認(rèn)選中第一個(gè)tab  
private int index = 1;  
// fragment管理類(lèi)  
private FragmentManager fragmentManager;  
// 三個(gè)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();  
}  

/** 
 * 設(shè)置默認(rèn)顯示的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);  
    }  
}  

/** 
 * 改變現(xiàn)象卡的選中狀態(tài) 
 */  
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;  
    }  
}  

每一個(gè)fragment對(duì)應(yīng)一個(gè)布局,點(diǎn)擊不同的按鈕來(lái)切換頁(yè)面。效果如下圖:


四、ViewPager + Fragment + FragmentPagerAdapter
如果想使用fragment的時(shí)候又想可以左右滑動(dòng),就可以使用這種方式。主要的部分就在viewpager的適配器。它的適配器繼承FragmentPagerAdapter.

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

需要傳入FragmentManager對(duì)象和一個(gè)存放fragment的list對(duì)象。

/** 
 * 初始化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);  
}  

對(duì)button添加點(diǎn)擊事件。

  @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;  
    }  
}  

我在布局文件中添加了一個(gè)imageview作為指示器。如果想第一種tab類(lèi)型界面的實(shí)現(xiàn)方式那樣在onPageSelected()方法中進(jìn)行設(shè)置,效果是只能當(dāng)頁(yè)面完全切換過(guò)來(lái)之后才能把指示器移動(dòng)過(guò)去。要想實(shí)現(xiàn)滑動(dòng)頁(yè)面的時(shí)候同時(shí)移動(dòng)指示器,就需要在onPageScrolled()方法中進(jìn)行設(shè)置。

 @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中的三個(gè)參數(shù)比較重要。第一個(gè)參數(shù)是position。它的含義是表示當(dāng)前顯示的界面中的第一個(gè)界面。意思就是的當(dāng)滑動(dòng)的時(shí)候,有可能出現(xiàn)兩個(gè)界面,position指的是左邊的界面。第二個(gè)參數(shù)是positionOffset指的是偏移量的比例,取值范圍是[0, 1)。第三個(gè)參數(shù)是positionOffsetPixels是指偏移的像素值。后兩個(gè)參數(shù)都相對(duì)頁(yè)面(一個(gè)page)來(lái)說(shuō)的。
我之前有看到過(guò)設(shè)置指示器的時(shí)候用的前兩個(gè)參數(shù)的,我也試了一下,OK的。不過(guò)感覺(jué)比較復(fù)雜,看了一下官方api,用第三個(gè)參數(shù)更簡(jiǎn)單。關(guān)鍵就是理解第一個(gè)參數(shù)position。用這種方法我只在代碼里有兩個(gè)判斷就可以完成了。
效果圖如下:


五、Viewpager + PagerTitleStrip / PagerTabStrip
這種方式?jīng)]有上一種效果好看,而且標(biāo)題變動(dòng)。不在詳細(xì)介紹。

六、Viewpager + TabLayout
TabLayout 是官方的,最好的是它可以兼容到2.2以上版本,包括2.2。很簡(jiǎn)單。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="match_parent"  
android:layout_height="match_parent"  
xmlns:app="http://schemas.android.com/apk/res-auto"  
android:orientation="vertical">  

<android.support.design.widget.TabLayout  
    android:id="@+id/tab_FindFragment_title"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:background="@color/titleBlue"  
    app:tabIndicatorColor="@color/white"  
    app:tabSelectedTextColor="@color/gray"  
    app:tabTextColor="@color/white"  
    />  


<android.support.v4.view.ViewPager  
    android:id="@+id/vp_FindFragment_pager"  
    android:layout_width="fill_parent"  
    android:layout_height="0dp"  
    android:layout_weight="1"  
    />  
</LinearLayout>  

這里面沒(méi)有什么特別的,就是添加了一個(gè)TabLayout和Viewpager作為上下的布局。其中

app:tabIndicatorColor="@color/white"                 // 下方滾動(dòng)的下劃線顏色  
app:tabSelectedTextColor="@color/gray"               // tab被選中后,文字的顏色  
app:tabTextColor="@color/white"                      // tab默認(rèn)的文字顏色  

因?yàn)檫@里面我每個(gè)欄目下,都會(huì)有一些列表,所以采用list<View>的方式,在里面切換layout不太適合,所以我采用了List<Fragment>來(lái)直接加載多個(gè)fragment

public class TabAdapter extends FragmentPagerAdapter {  

private List<Fragment> list_fragment;                         //fragment列表  
private List<String> list_Title;                              //tab名的列表  



public TabAdapter(FragmentManager fm,List<Fragment> list_fragment,List<String> 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();  
}  

//此方法用來(lái)顯示tab上的名字  
@Override  
public CharSequence getPageTitle(int position) {  

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

創(chuàng)建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<Fragment> list_fragment;                                //定義要裝fragment的列表  
private List<String> list_title;                                     //tab名稱(chēng)列表  


@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裝進(jìn)列表中  
    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));  

    //將名稱(chēng)加載tab名字列表,正常情況下,我們應(yīng)該在values/arrays.xml中進(jìn)行定義然后調(diào)用  
    list_title = new ArrayList<>();  
    list_title.add("tab1");  
    list_title.add("tab2");  
    list_title.add("tab3");  
  

    //設(shè)置TabLayout的模式  
    tab_FindFragment_title.setTabMode(TabLayout.MODE_FIXED);  
    //為T(mén)abLayout添加tab名稱(chēng)  
    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很像,不過(guò)有點(diǎn)過(guò)時(shí)了,不在詳細(xì)介紹。
八、FlycoTabLayout
這個(gè)是我見(jiàn)過(guò)的最好的,大家可以點(diǎn)擊看一下, 不在詳細(xì)介紹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容