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

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

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

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

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

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

   public static  Context context;
    /**
     * 中间内容的fragment
     */
    private Fragment frg_content;

    /**
     * fragmentTabHost
     */
    private FragmentTabHost frg_tabHost;

    /**
     * 定义数组来存放按钮图片
     */
    private int intImageViewArray[] = {
            R.drawable.selector_bt_bookstore_featured, R.drawable.selector_bt_bookstore_top,
            R.drawable.selector_bt_bookstore_category, R.drawable.selector_bt_bookstore_search
    };

    /**
     * 定义数组来存放Fragment界面
     */
    private Class fragmentArray[] = {
            BookstoreFeaturedFragment.class, BookstoreTopFragment.class,
            BookstoreCategoryFragment.class, BookstoreSearchFragment.class
    };

    /**
     * Tab选项卡的文字
     */
    private String txt_Array[] = {
            "精选", "排行", "分类", "搜索"
    };


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
	overridePendingTransition(R.anim.slide_right_in, R.anim.slide_mid_left_out);
			
	setContentView(R.layout.ac_bookstore_main);


        // 得到fragment的个数
        int count = intImageViewArray.length;

        // 实例化TabHost对象,得到TabHost
        frg_tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
        frg_tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        for (int i = 0; i < count; i++) {
            // 为每一个Tab按钮设置图标、文字和内容
              ImageView imageView = new ImageView(this);
//          imageView.setImageResource(intImageViewArray[i]);
            imageView.setImageDrawable(skinContext.getResources().getDrawable(intImageViewArray[i]));
            imageView.setScaleType(ScaleType.CENTER_CROP);
            TabSpec tabSpec = frg_tabHost.newTabSpec(txt_Array[i]).setIndicator(imageView);
            // 将Tab按钮添加进Tab选项卡中
              frg_tabHost.addTab(tabSpec, fragmentArray[i], null);
        }

        frg_tabHost.setCurrentTab(0);
        getSlidingMenu().setSlidingEnabled(false);

    }

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

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

tab显示在底部的布局:

  <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <FrameLayout
            android:id="@+id/realtabcontent"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />

        <android.support.v4.app.FragmentTabHost
            android:id="@android:id/tabhost"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="0" />
        </android.support.v4.app.FragmentTabHost>

     
    </LinearLayout>

tab显示在顶部的布局:

  <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <android.support.v4.app.FragmentTabHost
            android:id="@android:id/tabhost"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="0" />
        </android.support.v4.app.FragmentTabHost>

        <FrameLayout
            android:id="@+id/realtabcontent"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />
    </LinearLayout>

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

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

 

 public void switchContent(Fragment fragment) {

        getSupportFragmentManager().beginTransaction().replace(android.R.id.tabcontent, fragment)
                .commit();

    }

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

这样第一层tab就实现了。

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

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

viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器
viewpager_featured.setCurrentItem(0);

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

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

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

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

/**
	 * 设置侧滑数据
	 */
	private void setSlideMenu() {
		// 包含TextView的LinearLayout

		int two_width = 60;
		int three_width = 90;
		int four_width = 104;

		if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
				.getHeight(activity))) >= 1080 * 1720) {
			two_width = 120;
			three_width = 180;
			four_width = 200;

		} else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
				.getHeight(activity))) > 600 * 1280) {
			two_width = 90;
			three_width = 135;
			four_width = 156;

		} else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
				.getHeight(activity))) == 640 * 960) {

			two_width = 80;
			three_width = 125;
			four_width = 135;

		} else {
			two_width = 60;
			three_width = 90;
			four_width = 100;
		}

		// 参数设置
		LinearLayout.LayoutParams menuLinerLayoutParames = new LinearLayout.LayoutParams(four_width,
				LinearLayout.LayoutParams.MATCH_PARENT);
		menuLinerLayoutParames.gravity = Gravity.CENTER;
		menuLinerLayoutParames.leftMargin = 5;
		menuLinerLayoutParames.rightMargin = 5;

		LinearLayout.LayoutParams menuLinerLayoutParames1 = new LinearLayout.LayoutParams(two_width,
				LinearLayout.LayoutParams.MATCH_PARENT);
		menuLinerLayoutParames1.gravity = Gravity.CENTER;
		menuLinerLayoutParames1.leftMargin = 5;
		menuLinerLayoutParames1.rightMargin = 5;

		LinearLayout.LayoutParams menuLinerLayoutParames3 = new LinearLayout.LayoutParams(three_width,
				LinearLayout.LayoutParams.MATCH_PARENT);
		menuLinerLayoutParames3.gravity = Gravity.CENTER;
		menuLinerLayoutParames3.leftMargin = 5;
		menuLinerLayoutParames3.rightMargin = 5;

		// 添加TextView控件
		for (int i = 0; i < listChannelMenu.size(); i++) {
			TextView tvMenu = new TextView(activity);
			tvMenu.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
					LinearLayout.LayoutParams.MATCH_PARENT));
			tvMenu.setText(listChannelMenu.get(i).getChannelTypeName());
			tvMenu.setGravity(Gravity.CENTER);
			tvMenu.setTypeface(Typeface.SERIF);
			tvMenu.setTextSize(15);
			// tvMenu.setBackgroundResource(R.drawable.selector_bt_channel);

			tvMenu.setBackgroundDrawable((BookstoreActivity.context).getResources().getDrawable(
					R.drawable.selector_bt_channel));

			tvMenu.setOnClickListener(this);

			if (tvMenu.getText().toString().trim().length() == 2) {
				linearLayout_menu.addView(tvMenu, menuLinerLayoutParames1);
			} else if (tvMenu.getText().toString().trim().length() == 3) {
				linearLayout_menu.addView(tvMenu, menuLinerLayoutParames3);
			} else {
				linearLayout_menu.addView(tvMenu, menuLinerLayoutParames);
			}

			// 当点击上面的导航菜单时下方的控件的内容
			tvMenu.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					if (v.isClickable()) {
						TextView textMenu = (TextView) v;

						for (int i = 0; i < listChannelMenu.size(); i++) {
							if (textMenu.getText().toString().trim()
									.equals(listChannelMenu.get  (i).getChannelTypeName())) {
								// 选中菜单栏的菜单
								setSelectedState(i);
								// 点击菜单时改变内容
								viewpager_featured.setCurrentItem(i);
							}
						}
					}
				}
			});

		}

		viewPagerAdapter.addItem(listChannelMenu, true);

	}


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

设置适配器:

                           setSlideMenu();
			TextView mTextView = (TextView) linearLayout_menu.getChildAt(0);
			mTextView.setSelected(true);

			viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器
			viewpager_featured.setCurrentItem(0);


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

	viewpager_featured.setOnPageChangeListener(new OnPageChangeListener() {

			@SuppressLint("NewApi")
			@Override
			public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
				// if (blnFlag) {
				getMenuXPosition();
			}

			@Override
			public void onPageSelected(int position) {

				if (listMenuPosition == null || listMenuPosition.size() <= 0) {
					getMenuXPosition();
				}

				int moveLeft = (int) listMenuPosition.get(position) - (int) listMenuPosition.get(1);
				hScroll_menu.smoothScrollTo(moveLeft, 0);

				setSelectedState(position);

			}

			@Override
			public void onPageScrollStateChanged(int state) {

			}
		});
/**
	 * 存放菜单栏的位置
	 */
	private List<Integer> listMenuPosition;
	private void getMenuXPosition() {

		for (int i = 0; i < linearLayout_menu.getChildCount(); i++) {
			TextView textView = (TextView) linearLayout_menu.getChildAt(i);
			listMenuPosition.add(textView.getLeft());
		}

	}


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

  <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/bookstore_featured_menu_height"
        android:orientation="horizontal" >

        <HorizontalScrollView
            android:id="@+id/scrollview_menu"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:scrollbars="none" >

            <LinearLayout
                android:id="@+id/linearLayout_menu"
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:background="@drawable/bookstore_featured_navigation_bg"
                android:gravity="center_vertical"
                android:orientation="horizontal" >
            </LinearLayout>
        </HorizontalScrollView>

    </LinearLayout>

    <RelativeLayout
        android:id="@+id/relativelayout_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager_featured_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </android.support.v4.view.ViewPager>

        <ProgressBar
            android:id="@+id/progressBar_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" />
    </RelativeLayout>

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

 


 

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值