FragmentTabHost+Fragment+ViewPager实现内外层嵌套

转载,原博地址:http://blog.csdn.net/xiangxue336/article/details/22804971

今天介绍现在比较流行的一种app布局方式:内外层嵌套Tab,子Tab可以实现滑动切换。

    实现原理:FragmentTabHost+Fragment实现第一层Tab。

                    在Fragment里利用ViewPaper,实现第二层Tab,也就是子Tab。

    从原理可以看出,这两层Tab是完全解耦的,没有任何事件和数据联系,那么先介绍第一层怎么实现,由于google对FragmentTabHost+Fragment封装的比较好,实现过程无非是FragmentTabHost+Fragment的使用过程。

    可以用一句话来说明过程:就是给FragmentTabHost设置一定数量的按钮背景。

[java]  view plain copy
  1.    public static  Context context;  
  2.     /** 
  3.      * 中间内容的fragment 
  4.      */  
  5.     private Fragment frg_content;  
  6.   
  7.     /** 
  8.      * fragmentTabHost 
  9.      */  
  10.     private FragmentTabHost frg_tabHost;  
  11.   
  12.     /** 
  13.      * 定义数组来存放按钮图片 
  14.      */  
  15.     private int intImageViewArray[] = {  
  16.             R.drawable.selector_bt_bookstore_featured, R.drawable.selector_bt_bookstore_top,  
  17.             R.drawable.selector_bt_bookstore_category, R.drawable.selector_bt_bookstore_search  
  18.     };  
  19.   
  20.     /** 
  21.      * 定义数组来存放Fragment界面 
  22.      */  
  23.     private Class fragmentArray[] = {  
  24.             BookstoreFeaturedFragment.class, BookstoreTopFragment.class,  
  25.             BookstoreCategoryFragment.class, BookstoreSearchFragment.class  
  26.     };  
  27.   
  28.     /** 
  29.      * Tab选项卡的文字 
  30.      */  
  31.     private String txt_Array[] = {  
  32.             "精选""排行""分类""搜索"  
  33.     };  
  34.   
  35.   
  36.     @Override  
  37.     public void onCreate(Bundle savedInstanceState) {  
  38.         super.onCreate(savedInstanceState);  
  39.     overridePendingTransition(R.anim.slide_right_in, R.anim.slide_mid_left_out);  
  40.               
  41.     setContentView(R.layout.ac_bookstore_main);  
  42.   
  43.   
  44.         // 得到fragment的个数  
  45.         int count = intImageViewArray.length;  
  46.   
  47.         // 实例化TabHost对象,得到TabHost  
  48.         frg_tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);  
  49.         frg_tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);  
  50.   
  51.         for (int i = 0; i < count; i++) {  
  52.             // 为每一个Tab按钮设置图标、文字和内容  
  53.               ImageView imageView = new ImageView(this);  
  54. //          imageView.setImageResource(intImageViewArray[i]);  
  55.             imageView.setImageDrawable(skinContext.getResources().getDrawable(intImageViewArray[i]));  
  56.             imageView.setScaleType(ScaleType.CENTER_CROP);  
  57.             TabSpec tabSpec = frg_tabHost.newTabSpec(txt_Array[i]).setIndicator(imageView);  
  58.             // 将Tab按钮添加进Tab选项卡中  
  59.               frg_tabHost.addTab(tabSpec, fragmentArray[i], null);  
  60.         }  
  61.   
  62.         frg_tabHost.setCurrentTab(0);  
  63.         getSlidingMenu().setSlidingEnabled(false);  
  64.   
  65.     }  

这样就实现了点击哪个按钮,就显示哪个fragment。

这样就存在一个问题,就是tab布局问题,显示在上面还是下面:

tab显示在底部的布局:

[java]  view plain copy
  1. <LinearLayout  
  2.       android:layout_width="fill_parent"  
  3.       android:layout_height="fill_parent"  
  4.       android:orientation="vertical" >  
  5.   
  6.       <FrameLayout  
  7.           android:id="@+id/realtabcontent"  
  8.           android:layout_width="fill_parent"  
  9.           android:layout_height="0dip"  
  10.           android:layout_weight="1" />  
  11.   
  12.       <android.support.v4.app.FragmentTabHost  
  13.           android:id="@android:id/tabhost"  
  14.           android:layout_width="fill_parent"  
  15.           android:layout_height="wrap_content" >  
  16.   
  17.           <FrameLayout  
  18.               android:id="@android:id/tabcontent"  
  19.               android:layout_width="0dp"  
  20.               android:layout_height="0dp"  
  21.               android:layout_weight="0" />  
  22.       </android.support.v4.app.FragmentTabHost>  
  23.   
  24.      
  25.   </LinearLayout>  

tab显示在顶部的布局:

[java]  view plain copy
  1. <LinearLayout  
  2.       android:layout_width="fill_parent"  
  3.       android:layout_height="fill_parent"  
  4.       android:orientation="vertical" >  
  5.   
  6.       <android.support.v4.app.FragmentTabHost  
  7.           android:id="@android:id/tabhost"  
  8.           android:layout_width="fill_parent"  
  9.           android:layout_height="wrap_content" >  
  10.   
  11.           <FrameLayout  
  12.               android:id="@android:id/tabcontent"  
  13.               android:layout_width="0dp"  
  14.               android:layout_height="0dp"  
  15.               android:layout_weight="0" />  
  16.       </android.support.v4.app.FragmentTabHost>  
  17.   
  18.       <FrameLayout  
  19.           android:id="@+id/realtabcontent"  
  20.           android:layout_width="fill_parent"  
  21.           android:layout_height="0dip"  
  22.           android:layout_weight="1" />  
  23.   </LinearLayout>  

对比可以看出:realtabcontent是fragment显示的位置,一般是竖向填充:layout_weight="1"
                       tabhost是tab按钮放置位置,一般是横向填充,高度根据背景自适应。

                       tabcontent是干什么用的呢?看下代码:

 

[java]  view plain copy
  1. public void switchContent(Fragment fragment) {  
  2.   
  3.        getSupportFragmentManager().beginTransaction().replace(android.R.id.tabcontent, fragment)  
  4.                .commit();  
  5.   
  6.    }  

这行代码的作用是 显示frament页,所以我认为tabcontent指的是当前frament页面,可以用于页面的刷新。

这样第一层tab就实现了。

我们在实现第二层tab,其实即使ViewPaper的使用方法:

ViewPager的使用比较简单,完全可以当做一个listview使用:

[java]  view plain copy
  1. viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器  
  2. viewpager_featured.setCurrentItem(0);  

还可以设置缓存页面个数:viewpager_featured.setOffscreenPageLimit(2);用来防止页面刷新,这个数值越大会占用越多内存。所以放置数据刷新的方法是设置绑定数据的状态,根据数据状态觉得是否要刷新。

主要讲解下ViewPager和tab结合的时候的使用,特别是有动画效果的时候的使用。

这里介绍一种tab实现方式:1.tab 个数可删减。2、焦点tab显示在可见位置

这里tab按钮用textview来实现,先动态的初始化tab个数,以及根据显示字数多少设置宽度:

[java]  view plain copy
  1. /** 
  2.      * 设置侧滑数据 
  3.      */  
  4.     private void setSlideMenu() {  
  5.         // 包含TextView的LinearLayout  
  6.   
  7.         int two_width = 60;  
  8.         int three_width = 90;  
  9.         int four_width = 104;  
  10.   
  11.         if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils  
  12.                 .getHeight(activity))) >= 1080 * 1720) {  
  13.             two_width = 120;  
  14.             three_width = 180;  
  15.             four_width = 200;  
  16.   
  17.         } else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils  
  18.                 .getHeight(activity))) > 600 * 1280) {  
  19.             two_width = 90;  
  20.             three_width = 135;  
  21.             four_width = 156;  
  22.   
  23.         } else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils  
  24.                 .getHeight(activity))) == 640 * 960) {  
  25.   
  26.             two_width = 80;  
  27.             three_width = 125;  
  28.             four_width = 135;  
  29.   
  30.         } else {  
  31.             two_width = 60;  
  32.             three_width = 90;  
  33.             four_width = 100;  
  34.         }  
  35.   
  36.         // 参数设置  
  37.         LinearLayout.LayoutParams menuLinerLayoutParames = new LinearLayout.LayoutParams(four_width,  
  38.                 LinearLayout.LayoutParams.MATCH_PARENT);  
  39.         menuLinerLayoutParames.gravity = Gravity.CENTER;  
  40.         menuLinerLayoutParames.leftMargin = 5;  
  41.         menuLinerLayoutParames.rightMargin = 5;  
  42.   
  43.         LinearLayout.LayoutParams menuLinerLayoutParames1 = new LinearLayout.LayoutParams(two_width,  
  44.                 LinearLayout.LayoutParams.MATCH_PARENT);  
  45.         menuLinerLayoutParames1.gravity = Gravity.CENTER;  
  46.         menuLinerLayoutParames1.leftMargin = 5;  
  47.         menuLinerLayoutParames1.rightMargin = 5;  
  48.   
  49.         LinearLayout.LayoutParams menuLinerLayoutParames3 = new LinearLayout.LayoutParams(three_width,  
  50.                 LinearLayout.LayoutParams.MATCH_PARENT);  
  51.         menuLinerLayoutParames3.gravity = Gravity.CENTER;  
  52.         menuLinerLayoutParames3.leftMargin = 5;  
  53.         menuLinerLayoutParames3.rightMargin = 5;  
  54.   
  55.         // 添加TextView控件  
  56.         for (int i = 0; i < listChannelMenu.size(); i++) {  
  57.             TextView tvMenu = new TextView(activity);  
  58.             tvMenu.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,  
  59.                     LinearLayout.LayoutParams.MATCH_PARENT));  
  60.             tvMenu.setText(listChannelMenu.get(i).getChannelTypeName());  
  61.             tvMenu.setGravity(Gravity.CENTER);  
  62.             tvMenu.setTypeface(Typeface.SERIF);  
  63.             tvMenu.setTextSize(15);  
  64.             // tvMenu.setBackgroundResource(R.drawable.selector_bt_channel);  
  65.   
  66.             tvMenu.setBackgroundDrawable((BookstoreActivity.context).getResources().getDrawable(  
  67.                     R.drawable.selector_bt_channel));  
  68.   
  69.             tvMenu.setOnClickListener(this);  
  70.   
  71.             if (tvMenu.getText().toString().trim().length() == 2) {  
  72.                 linearLayout_menu.addView(tvMenu, menuLinerLayoutParames1);  
  73.             } else if (tvMenu.getText().toString().trim().length() == 3) {  
  74.                 linearLayout_menu.addView(tvMenu, menuLinerLayoutParames3);  
  75.             } else {  
  76.                 linearLayout_menu.addView(tvMenu, menuLinerLayoutParames);  
  77.             }  
  78.   
  79.             // 当点击上面的导航菜单时下方的控件的内容  
  80.             tvMenu.setOnClickListener(new OnClickListener() {  
  81.   
  82.                 @Override  
  83.                 public void onClick(View v) {  
  84.                     if (v.isClickable()) {  
  85.                         TextView textMenu = (TextView) v;  
  86.   
  87.                         for (int i = 0; i < listChannelMenu.size(); i++) {  
  88.                             if (textMenu.getText().toString().trim()  
  89.                                     .equals(listChannelMenu.get  (i).getChannelTypeName())) {  
  90.                                 // 选中菜单栏的菜单  
  91.                                 setSelectedState(i);  
  92.                                 // 点击菜单时改变内容  
  93.                                 viewpager_featured.setCurrentItem(i);  
  94.                             }  
  95.                         }  
  96.                     }  
  97.                 }  
  98.             });  
  99.   
  100.         }  
  101.   
  102.         viewPagerAdapter.addItem(listChannelMenu, true);  
  103.   
  104.     }  


根据屏幕大小动态计算了,textview按钮的属性。并且设置了点击监听,根据tab的数量给adapter绑定数据。

设置适配器:

[java]  view plain copy
  1.                         setSlideMenu();  
  2. TextView mTextView = (TextView) linearLayout_menu.getChildAt(0);  
  3. mTextView.setSelected(true);  
  4.   
  5. viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器  
  6. viewpager_featured.setCurrentItem(0);  


这样点击tab,ViewPaper可以自动切换了,那滑动ViewPapert,tab调整显示位置实现:

[java]  view plain copy
  1. viewpager_featured.setOnPageChangeListener(new OnPageChangeListener() {  
  2.   
  3.         @SuppressLint("NewApi")  
  4.         @Override  
  5.         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  6.             // if (blnFlag) {  
  7.             getMenuXPosition();  
  8.         }  
  9.   
  10.         @Override  
  11.         public void onPageSelected(int position) {  
  12.   
  13.             if (listMenuPosition == null || listMenuPosition.size() <= 0) {  
  14.                 getMenuXPosition();  
  15.             }  
  16.   
  17.             int moveLeft = (int) listMenuPosition.get(position) - (int) listMenuPosition.get(1);  
  18.             hScroll_menu.smoothScrollTo(moveLeft, 0);  
  19.   
  20.             setSelectedState(position);  
  21.   
  22.         }  
  23.   
  24.         @Override  
  25.         public void onPageScrollStateChanged(int state) {  
  26.   
  27.         }  
  28.     });  
[java]  view plain copy
  1. /** 
  2.      * 存放菜单栏的位置 
  3.      */  
  4.     private List<Integer> listMenuPosition;  
  5.     private void getMenuXPosition() {  
  6.   
  7.         for (int i = 0; i < linearLayout_menu.getChildCount(); i++) {  
  8.             TextView textView = (TextView) linearLayout_menu.getChildAt(i);  
  9.             listMenuPosition.add(textView.getLeft());  
  10.         }  
  11.   
  12.     }  


是通过记录每个textview的左侧位置,每次滑动的时候都都让scrollview滑动一定位置,保证焦点textview 的tab可见。最后给出布局文件:

[java]  view plain copy
  1. <LinearLayout  
  2.       android:layout_width="match_parent"  
  3.       android:layout_height="@dimen/bookstore_featured_menu_height"  
  4.       android:orientation="horizontal" >  
  5.   
  6.       <HorizontalScrollView  
  7.           android:id="@+id/scrollview_menu"  
  8.           android:layout_width="0dip"  
  9.           android:layout_height="wrap_content"  
  10.           android:layout_weight="1"  
  11.           android:scrollbars="none" >  
  12.   
  13.           <LinearLayout  
  14.               android:id="@+id/linearLayout_menu"  
  15.               android:layout_width="0dip"  
  16.               android:layout_height="match_parent"  
  17.               android:background="@drawable/bookstore_featured_navigation_bg"  
  18.               android:gravity="center_vertical"  
  19.               android:orientation="horizontal" >  
  20.           </LinearLayout>  
  21.       </HorizontalScrollView>  
  22.   
  23.   </LinearLayout>  
  24.   
  25.   <RelativeLayout  
  26.       android:id="@+id/relativelayout_viewpager"  
  27.       android:layout_width="match_parent"  
  28.       android:layout_height="match_parent" >  
  29.   
  30.       <android.support.v4.view.ViewPager  
  31.           android:id="@+id/viewpager_featured_pager"  
  32.           android:layout_width="match_parent"  
  33.           android:layout_height="match_parent" >  
  34.       </android.support.v4.view.ViewPager>  
  35.   
  36.       <ProgressBar  
  37.           android:id="@+id/progressBar_loading"  
  38.           android:layout_width="wrap_content"  
  39.           android:layout_height="wrap_content"  
  40.           android:layout_centerInParent="true" />  
  41.   </RelativeLayout>  

和ViewPaper配合实现tab的方式有很多,关键根据需求不同来选择实现方式,textview、button、radiobutton、iamgeview都可以用来实现tab。

你可能感兴趣的:(FragmentTabHost+Fragment+ViewPager实现内外层嵌套)