zoukankan      html  css  js  c++  java
  • Android UI 之 Tab类型界面总结

    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.   
    7.     <TabHost  
    8.         android:id="@android:id/tabhost"  
    9.         android:layout_width="match_parent"  
    10.         android:layout_height="match_parent" >  
    11.   
    12.         <RelativeLayout  
    13.             android:layout_width="match_parent"  
    14.             android:layout_height="match_parent"  
    15.             android:orientation="vertical" >  
    16.   
    17.             <!-- 可以指定tabwidget的位置    android:layout_alignParentBottom="true" -->  
    18.   
    19.             <TabWidget  
    20.                 android:id="@android:id/tabs"  
    21.                 android:layout_width="match_parent"  
    22.                 android:layout_height="wrap_content"  
    23.                 android:layout_alignParentBottom="false" >  
    24.             </TabWidget>  
    25.   
    26.             <FrameLayout  
    27.                 android:id="@android:id/tabcontent"  
    28.                 android:layout_width="match_parent"  
    29.                 android:layout_height="match_parent"  
    30.                 android:layout_below="@android:id/tabs" >  
    31.   
    32.                 <LinearLayout  
    33.                     android:id="@+id/tab1"  
    34.                     android:layout_width="match_parent"  
    35.                     android:layout_height="match_parent"  
    36.                     android:background="#DEB887"  
    37.                     android:orientation="vertical" >  
    38.                 </LinearLayout>  
    39.   
    40.                 <LinearLayout  
    41.                     android:id="@+id/tab2"  
    42.                     android:layout_width="match_parent"  
    43.                     android:layout_height="match_parent"  
    44.                     android:background="#BCEE68"  
    45.                     android:orientation="vertical" >  
    46.                 </LinearLayout>  
    47.   
    48.                 <LinearLayout  
    49.                     android:id="@+id/tab3"  
    50.                     android:layout_width="match_parent"  
    51.                     android:layout_height="match_parent"  
    52.                     android:background="#7D9EC0"  
    53.                     android:orientation="vertical" >  
    54.                 </LinearLayout>  
    55.             </FrameLayout>  
    56.         </RelativeLayout>  
    57.     </TabHost>  
    58.   
    59. </LinearLayout>  

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

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


    二、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.   
    11.         viewPager.setAdapter(pagerAdapter);  
    12.         viewPager.setOnPageChangeListener(new OnPageChangeListener() {  
    13.             @Override  
    14.             public void onPageSelected(int arg0) {  
    15.                 setDots(arg0);  
    16.             }  
    17.   
    18.             @Override  
    19.             public void onPageScrolled(int arg0, float arg1, int arg2) {  
    20.             }  
    21.   
    22.             @Override  
    23.             public void onPageScrollStateChanged(int arg0) {  
    24.             }  
    25.         });  
    26.     }  
    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.   
    23.     };  

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

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

    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.      */  
    17.     private void setDots(int position) {  
    18.         if (position < 0 || position > list.size() - 1  
    19.                 || currentIndex == position) {  
    20.             return;  
    21.         }  
    22.         dots[position].setBackgroundResource(R.drawable.dian_down);  
    23.         dots[currentIndex].setBackgroundResource(R.drawable.dian);  
    24.         currentIndex = position;  
    25.     }  

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

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

     

    四、ViewPager + Fragment + FragmentPagerAdapter

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

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

        需要传入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.   
    14.         viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(),  
    15.                 fragmentsList));  
    16.         viewPager.setCurrentItem(0);  
    17.         viewPager.setOnPageChangeListener(this);  
    18.     }  


        对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.   
    7.     <android.support.v4.view.ViewPager  
    8.         android:id="@+id/fifth_vp"  
    9.         android:layout_width="wrap_content"  
    10.         android:layout_height="wrap_content"  
    11.         android:layout_gravity="center" >  
    12.   
    13.         <android.support.v4.view.PagerTabStrip  
    14.             android:id="@+id/fifth_strip"  
    15.             android:layout_width="wrap_content"  
    16.             android:layout_height="wrap_content"  
    17.             android:layout_gravity="top"  
    18.             android:background="#7EC0EE"  
    19.             android:padding="10dip" />  
    20.     </android.support.v4.view.ViewPager>  
    21.   
    22. </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

  • 相关阅读:
    使用tensorflow深度学习识别验证码
    单线程、多线程、多进程、协程比较,以爬取新浪军事历史为例
    web开发中的安全问题
    关于无效验证码
    怎么制作免费短信轰炸机
    python2.7中关于编码,json格式的中文输出显示
    一个网址
    基于pyteseract google ocr的图形验证码识别
    python使用pyqt写带界面工具
    python使用tkinter写带界面的工具
  • 原文地址:https://www.cnblogs.com/kluan/p/4828218.html
Copyright © 2011-2022 走看看