Tab菜单栏:FragmentTabHost&ViewPager&Fragment的结合使用

本文介绍了如何在Android应用中结合使用FragmentTabHost、ViewPager和Fragment,通过实例代码展示了如何创建标签切换和Fragment滑动切换的效果。在实际操作中需要注意FragmentTabHost与ViewPager的初始化顺序,以及解决可能出现的Fragment显示顺序、重叠和大小问题。
摘要由CSDN通过智能技术生成

技术拆分

Fragment

Fragment相信大家都不陌生。此处我们用它来存放页面主体所要显示的内容。
实现方式:
在自定义的Fragment类中,重写OnCreateView()方法。在该方法中通过LayoutInflater来Inflate该Fragment的布局文件,赋值给View对象并返回该对象。
Fragment的难点:生命周期。
为了照顾Newcomer,转载一段关于Fragment的介绍:
Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板神马超级大屏的。难道无法做到一个App可以同时适应手机和平板么,当然了,必须有啊。Fragment的出现就是为了解决这样的问题。你可以把Fragment当成Activity的一个界面的一个组成部分,甚至Activity的界面可以完全有不同的Fragment组成,更帅气的是Fragment拥有自己的生命周期和接收、处理用户的事件,这样就不必在Activity写一堆控件的事件处理的代码了。更为重要的是,你可以动态的添加、替换和移除某个Fragment。

FragmentTabhost

实现标签卡的切换。通过简单的封装替代早期使用的TabHost(Android3.0以后被废弃)。
实现方式:
1. 通过findViewById()方法实例化FragmentTabhost对象
2. 通过setup(Context context, FragmentManager manager, int containerId)方法初始化对象
3. 通过给每个Tab按钮设置标签、图标和文字,并添加至Tab选项卡中,同时绑定Fragment
4. 通过setOnTabChangedListener(OnTabChangedListener listener)监听Tab按钮的改变,控制显示相应的Fragment

ViewPager

作为Fragment的实际容器,用于左右切换当前的View(即实现Fragment的滑动切换效果)。
实现方式:
1. 通过findViewById()方法实例化ViewPager对象
2. 设置并绑定FragmentPagerAdapter适配器。
3. 通过setOnPageChangedListener(OnPageChangedListener listener)来监听ViewPager显示内容的变化,控制FragmentTabHost标签随之切换

代码示例

布局文件

activity_main.xml(MainActivity布局文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.wolfgy.test.fragmenttabhostviewpagerfragment.MainActivity">

    <android.support.v4.app.FragmentTabHost
        android:id="@+id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
    />
</LinearLayout>

content_tab.xml(菜单栏布局文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/tab_text"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

fragment_first.xml(Fragment布局文件)
(其他Fragment布局文件不重复列出)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="FirstFrom三汪"/>
</LinearLayout>

Java代码

FragmentFirst.java(自定义每个Fragment)
(不重复列出其他Fragment代码文件)

package com.wolfgy.test.fragmenttabhostviewpagerfragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentFirst extends Fragment {

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

MyFragmentPagerAdapter.java(ViewPager适配器)

package com.wolfgy.test.fragmenttabhostviewpagerfragment;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.util.Log;
import android.view.ViewGroup;

import java.util.List;


public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    List<Fragment> list;
    public MyFragmentPagerAdapter(FragmentManager fm,List list){
        super(fm);
        this.list = list;
    }
    @Override
    public Fragment getItem(int position) {
        return list.get(position);
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment)super.instantiateItem(container, position);
        return fragment;
    }
}

MainActivity.java(MainActivity代码)

package com.wolfgy.test.fragmenttabhostviewpagerfragment;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TabHost;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity {
    FragmentTabHost fragmentTabHost;
    ViewPager viewPager;
    String[] titles  = {"first","second","third"};
    Class[] classes =   {FragmentFirst.class,FragmentSecond.class,FragmentThird.class};
    List<Fragment> list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化Fragment并放入集合
        initFragment();
        //获取屏幕宽高
        DisplayMetrics dm =  new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int height = dm.heightPixels;
        int width = dm.widthPixels;
        //初始化ViewPager
        viewPager = (ViewPager)findViewById(R.id.viewpager);
        viewPager.setAdapter(new MyFragmentPagerAdapter (getSupportFragmentManager(),list));
        //初始化FragmentTabHost
        fragmentTabHost = (FragmentTabHost) findViewById(R.id.tabhost);
        fragmentTabHost.setup(this,getSupportFragmentManager    (),R.id.viewpager);
        int arrayCount = titles.length;
        for (int i=0;i<arrayCount;i++){
            //给每个Tab设置标签、内容
            TabHost.TabSpec tabSpec = fragmentTabHost.newTabSpec(titles [i]).setIndicator(getTabItemView(i));
            //将Tab绑定进Tab选项卡中,并绑定Fragment
            fragmentTabHost.addTab(tabSpec,classes[i],null);
            fragmentTabHost.setTag(i);
        }

        //当前标签改变监听
        fragmentTabHost.setOnTabChangedListener(new     TabHost.OnTabChangeListener() {
            @Override
            public void onTabChanged(String s) {
                int position = fragmentTabHost.getCurrentTab();
                viewPager.setCurrentItem(position);
            }
        });

        //设置viewPager改变监听
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener    () {
            @Override
            public void onPageScrolled(int position, float positionOffset,  int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                fragmentTabHost.setCurrentTab(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

    }

    private void initFragment(){
        Fragment fragment1 = new FragmentFirst();
        Fragment fragment2 = new FragmentSecond();
        Fragment fragment3 = new FragmentThird();
        list.add(fragment1);
        list.add(fragment2);
        list.add(fragment3);
    }
    /**
     * 初始化并返回Tab子布局
     */
    private View getTabItemView(int position){
        View view = LayoutInflater.from(MainActivity.this).inflate  (R.layout.content_tab,null);
        TextView textView = (TextView) view.findViewById(R.id.tab_text);
        textView.setText(titles[position]);
        return view;
    }
}   

细节说明

ViewPager和FragmentTabHost的初始化顺序

刚开始接触到这个的时候,出现了一个我百思不得其解的Bug——ClassCastException,浪费了我不少时间。
系统提示是这样的:
android.widget.FrameLayout cannot be cast to android.support.v4.view.ViewPager
看了很多论坛和网站的相关问题。基本都是实例化布局的时候,引用了错误的布局ID。但显然我犯的并不是这种低级错误 。
最后在自己调试的时候,我发现把ViewPager和FragmentTabHost的初始化顺序改变一下,就不报错了。
情况应该是FragmentTabHost在初始化的时候自动给Fragment定义了FrameLayout容器,在后面要把Fragment放入ViewPager的时候便无法通过。而如果先把ViewPager进行初始化以及绑定FragmentPagerAdapter,此时初始化FragmentTabHost,则自然而然地选择了ViewPager作为Fragment的容器。
因此,在使用的时候一定要注意二者的初始化顺序。

Fragment的显示顺序

不知道为什么。标签页默认从第二页开始显示,试过在MainActivity里设置完适配器以后用

viewPager.setCurrentItem(0);

如我所料,没有任何效果。这是我碰到的第一个问题。
如果仁兄知道原因和解决方式,欢迎评论分享。多谢。

Fragment的重叠

如果你是自己手打的代码,不是copy我的代码,你可能会遇到三个Fragment重叠在一起显示的问题。对于这种情况,我的解决方式是给每个Fragment布局添加背景色。这样就不会重叠显示了。

Fragment的大小问题

当你运行demo的时候你可能会发现Fragment的大小不能充满屏幕(如果你如上文所说添加了背景色并且Fragment布局文件中的内容不能够充满屏幕时),就算。
在Fragment的java代码中,我一开始是这样子重写onCreateView()方法的

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_first,null);
    return view;
}

熟悉LayoutInflater的朋友都知道,这种写法会导致该布局中的layout__height等一系列大小参数失效,变成wrap_content。
因此我把它改成了

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_first,container,false);
    return view;
}

但是也没有任何效果。
我想可能是因为我们装Fragment的容器是ViewPager,相对来说比较特殊。

我的下一个尝试是在MainActivity中获取屏幕宽高,然后通过setArguments方法传入屏幕宽高,然后给Fragment的view设置setMinimumHeight和setMinimumWidth。(你还能在我上传的代码中看到没有删除的获取屏幕宽高的代码)
但是也没有效果。若是有仁兄知道解决方法,也欢迎分享。拜谢再三。
相应的代码片段如下:
这是在MainActivity的onCreate()方法中的代码

//获取屏幕宽高
DisplayMetrics dm =  new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
height = dm.heightPixels;
width = dm.widthPixels;
//初始化Fragment并放入集合
initFragment();

这是初始化Fragment的方法

private void initFragment(){
    Bundle bundle = new Bundle();
    bundle.putInt("height",height);
    bundle.putInt("width",width);
    Fragment fragment1 = new FragmentFirst();
    Fragment fragment2 = new FragmentSecond();
    Fragment fragment3 = new FragmentThird();
    fragment1.setArguments(bundle);
    fragment2.setArguments(bundle);
    fragment3.setArguments(bundle);
    list.add(fragment1);
    list.add(fragment2);
    list.add(fragment3);
}

Fragment类

package com.wolfgy.test.fragmenttabhostviewpagerfragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by Administrator on 2017/1/2.
 */
public class FragmentFirst extends Fragment {
    int height,width;
    Bundle bundle;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {
        View view = inflater.inflat(R.layout.fragment_first,container,false);
        bundle = getArguments();
        height = bundle.getInt("height");
        width = bundle.getInt("width");
        view.setMinimumHeight(height);
        view.setMinimumWidth(width);
        return view;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值