Fragment是一种可以嵌入在活动当中的UI 片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。拥有自己的生命周期和接收、处理用户的事件。你可以动态的添加、替换和移除某个Fragment。

Fragment使用非常广泛,在此不介绍Fragment的生命周期,本例子将使用Fragment实现如下效果:

Message Friend Setting

图一


Message Friend Setting

图二


Message Friend Setting

图三


底部的三个按钮分别控制三个Fragment的展示,为方便说明,底部三个按钮从左至右命名为Message、Friend、Setting,如上面三张图所示。

图三的上部是展现使用ViewPager的效果,加了一条蓝色的指示器。

bottombar的布局文件

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><RelativeLayoutandroid:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"><Buttonandroid:id="@+id/btn_messaage"android:layout_width="40dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/message1_normal"/></RelativeLayout><RelativeLayoutandroid:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"><Buttonandroid:id="@+id/btn_friend"android:layout_width="40dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/friend_normal"/></RelativeLayout><RelativeLayoutandroid:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"><Buttonandroid:id="@+id/btn_setting"android:layout_width="40dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/setting_normal"/></RelativeLayout></LinearLayout>

topbar的布局文件

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><RelativeLayoutandroid:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"><Buttonandroid:id="@+id/btn_insect"android:layout_width="40dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/insect"/></RelativeLayout><RelativeLayoutandroid:layout_width="0dp"android:layout_height="40dp"android:layout_weight="1"><Buttonandroid:id="@+id/btn_menu"android:layout_width="40dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/menu"/></RelativeLayout></LinearLayout>

MainActivity的布局文件

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"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.jam.fragmentdemo.MainActivity"><includeandroid:id="@+id/bottombar"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"layout="@layout/bottombar"/><FrameLayoutandroid:id="@+id/content"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@id/bottombar"/></RelativeLayout>

由于message和friend两个fragment的布局文件简单,所以在此就不贴上来了。

SettingFragment的布局文件

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><includeandroid:layout_width="match_parent"android:layout_height="wrap_content"layout="@layout/topbar"/><ImageViewandroid:id="@+id/iv_tabline"android:layout_width="match_parent"android:layout_height="3dp"android:layout_marginLeft="0dp"android:background="@drawable/tabline"/><android.support.v4.view.ViewPagerandroid:id="@+id/setting_fragment_viewpager"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_weight="1.0"android:flipInterval="30"android:persistentDrawingCache="animation"/></LinearLayout>

MainActivity代码:

packagecom.jam.fragmentdemo;importandroid.os.Bundle;importandroid.support.v4.app.FragmentActivity;importandroid.support.v4.app.FragmentManager;importandroid.support.v4.app.FragmentTransaction;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.view.Window;importandroid.widget.Button;/***由于这个工程还需要用到ViewPager,所以在此继承FragmentActivity*@authorJam**/publicclassMainActivityextendsFragmentActivityimplementsOnClickListener{//三个按钮privateButtonmessageButton;privateButtonfriendButton;privateButtonsettingButton;//三个fragmentprivateMessageFragmentmessgeFragment;privateFriendFragmentfriendFragment;privateSettingFragmentsettingFragment;privateintfragmentIndex=0;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);messageButton=(Button)findViewById(R.id.btn_messaage);friendButton=(Button)findViewById(R.id.btn_friend);settingButton=(Button)findViewById(R.id.btn_setting);setDefaultFragment();//为三个按钮绑定监听器messageButton.setOnClickListener(this);friendButton.setOnClickListener(this);settingButton.setOnClickListener(this);}/***设置初始化默认的Fragment为MessageFragment*/privatevoidsetDefaultFragment(){FragmentManagerfragmentManager=getSupportFragmentManager();FragmentTransactiontransaction=fragmentManager.beginTransaction();messgeFragment=newMessageFragment();transaction.replace(R.id.content,messgeFragment);transaction.commit();}/***在下面的onClick内,用了两个switch语句来处理页面的更换第一层判断按下了哪一个按钮*第二层判断当前页是哪一页,在决定隐藏哪一页*这里的实现方法可能会不太灵活*/@OverridepublicvoidonClick(Viewv){//FragmentTransaction每一次都需要拿到,否则程序会报错FragmentTransactiontransaction=getSupportFragmentManager().beginTransaction();switch(v.getId()){caseR.id.btn_messaage:if(messgeFragment==null){messgeFragment=newMessageFragment();transaction.add(R.id.content,messgeFragment);}switch(fragmentIndex){case0:if(messgeFragment!=null){transaction.hide(messgeFragment);}break;case1:if(friendFragment!=null){transaction.hide(friendFragment);}break;case2:if(settingFragment!=null){transaction.hide(settingFragment);}break;}transaction.show(messgeFragment);fragmentIndex=0;break;caseR.id.btn_friend:if(friendFragment==null){friendFragment=newFriendFragment();transaction.add(R.id.content,friendFragment);}switch(fragmentIndex){case0:if(messgeFragment!=null){transaction.hide(messgeFragment);}break;case1:if(friendFragment!=null){transaction.hide(friendFragment);}break;case2:if(settingFragment!=null){transaction.hide(settingFragment);}break;}transaction.show(friendFragment);fragmentIndex=1;break;caseR.id.btn_setting:if(settingFragment==null){settingFragment=newSettingFragment();transaction.add(R.id.content,settingFragment);}switch(fragmentIndex){case0:if(messgeFragment!=null){transaction.hide(messgeFragment);}break;case1:if(friendFragment!=null){transaction.hide(friendFragment);}break;case2:if(settingFragment!=null){transaction.hide(settingFragment);}break;}transaction.show(settingFragment);fragmentIndex=2;break;}transaction.commit();}}

这段代码中要注意,在做事务操作时FragmentTransaction每次都要拿到,即

FragmentTransactiontransaction=getSupportFragmentManager().beginTransaction();

否则程序会报错,完成操作记得transaction.commit();

另外在使用流程大致如下

首先


FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

(注意上面getSupportFragmentManager是V4包的用法)


transaction.add()

往Activity中添加一个Fragment

transaction.remove()

从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。

transaction.replace()

使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~

transaction.hide()

隐藏当前的Fragment,仅仅是设为不可见,并不会销毁

transaction.show()

显示之前隐藏的Fragment

detach()

会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。

attach()

重建view视图,附加到UI上并显示。


transatcion.commit()//提交一个事务


以上是大致流程,具体使用哪种方法依照自己的工程需要。


MessageFragment的代码和FriendFragment的代码简单,没有在其中添加什么东西,只需要让他们继承Fragment

在此只贴出其中MessageFragment的代码

packagecom.jam.fragmentdemo;importandroid.os.Bundle;importandroid.support.annotation.Nullable;importandroid.support.v4.app.Fragment;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;publicclassMessageFragmentextendsFragment{@OverridepublicViewonCreateView(LayoutInflaterinflater,@NullableViewGroupcontainer,@NullableBundlesavedInstanceState){//TODOAuto-generatedmethodstubreturninflater.inflate(R.layout.activity_messagefragment,container,false);}}

SettingFragment由于用到了ViewPager,所以代码比前面两个Fragment多

SettingFragment的代码:

packagecom.jam.fragmentdemo;importjava.util.ArrayList;importandroid.os.Bundle;importandroid.support.annotation.Nullable;importandroid.support.v4.app.Fragment;importandroid.support.v4.app.FragmentManager;importandroid.support.v4.app.FragmentPagerAdapter;importandroid.support.v4.view.ViewPager;importandroid.support.v4.view.ViewPager.OnPageChangeListener;importandroid.util.DisplayMetrics;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.view.ViewGroup;importandroid.view.ViewGroup.LayoutParams;importandroid.view.animation.Animation;importandroid.view.animation.TranslateAnimation;importandroid.widget.Button;importandroid.widget.ImageView;importcom.jam.fragmentdemo.settingcontent.InsectFragment;importcom.jam.fragmentdemo.settingcontent.MenuFragment;publicclassSettingFragmentextendsFragmentimplementsOnClickListener{//TopBar所含有的页数privatefinalstaticintpagerNum=2;//TopBar当前所指向的页下标privateintcurrentIndex=0;//initTabLineWith方法中计算得到的平均值用avg记录//这里的平均值指的是:屏幕宽度/所含的页数(pagerNum)privateintavg;privateArrayList<Fragment>list=newArrayList<Fragment>();privateViewPagerviewPager;privateImageViewtabLine;privateInsectFragmentinsectFragment;privateMenuFragmentmenuFragment;privateButtoninsectButton;privateButtonmenuButton;@OverridepublicViewonCreateView(LayoutInflaterinflater,@NullableViewGroupcontainer,@NullableBundlesavedInstanceState){Viewview=inflater.inflate(R.layout.activity_settingfragment,null);initTabLineWith(view);//初始化部件viewPager=(ViewPager)view.findViewById(R.id.setting_fragment_viewpager);viewPager.setCurrentItem(0);insectButton=(Button)view.findViewById(R.id.btn_insect);menuButton=(Button)view.findViewById(R.id.btn_menu);insectFragment=newInsectFragment();menuFragment=newMenuFragment();list.add(insectFragment);list.add(menuFragment);insectButton.setOnClickListener(this);menuButton.setOnClickListener(this);viewPager.setAdapter(newMyViewPagerAdapter(getChildFragmentManager(),list));viewPager.setOnPageChangeListener(newOnPageChangeListener(){/***tabLine指示器使用Animation的方法移动*/@OverridepublicvoidonPageSelected(intposition){Animationanimation=null;switch(position){case0:animation=newTranslateAnimation(currentIndex*avg,0*avg,0,0);break;case1:animation=newTranslateAnimation(currentIndex*avg,1*avg,0,0);break;}currentIndex=position;animation.setFillAfter(true);animation.setDuration(300);tabLine.startAnimation(animation);}@OverridepublicvoidonPageScrolled(intarg0,floatarg1,intarg2){}@OverridepublicvoidonPageScrollStateChanged(intarg0){}});returnview;}/***根据屏幕宽度的大小,初始化TabLine的长度*@paramview*/privatevoidinitTabLineWith(Viewview){tabLine=(ImageView)view.findViewById(R.id.iv_tabline);LayoutParamslp=(LayoutParams)tabLine.getLayoutParams();//拿到屏幕宽度的操作DisplayMetricsdm=newDisplayMetrics();getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);intscreenWith=dm.widthPixels;avg=screenWith/pagerNum;lp.width=avg;//设置tabLine指示器的长度tabLine.setLayoutParams(lp);}/***点击改动当前页面*/@OverridepublicvoidonClick(Viewv){switch(v.getId()){caseR.id.btn_insect:viewPager.setCurrentItem(0);currentIndex=0;break;caseR.id.btn_menu:viewPager.setCurrentItem(1);currentIndex=1;break;}}publicclassMyViewPagerAdapterextendsFragmentPagerAdapter{privateArrayList<Fragment>fragmentsList;publicMyViewPagerAdapter(FragmentManagerfm){super(fm);}publicMyViewPagerAdapter(FragmentManagerfm,ArrayList<Fragment>list){super(fm);this.fragmentsList=list;}@OverridepublicintgetCount(){returnfragmentsList.size();}@OverridepublicFragmentgetItem(intarg0){returnfragmentsList.get(arg0);}@OverridepublicintgetItemPosition(Objectobject){returnsuper.getItemPosition(object);}}}

SettingFragment中又包含两个Fragment,这两个Fragment没什么内容,在此就不贴布局文件和代码了。


单纯使用Fragment,不能实现滑动的效果,只能点击切换,要实现滑动的效果可考虑使用ViewPager。


使用Fragment实现这种类似TabHost,好处在于文件方便管理,每一个Fragment都是独立的,单纯的使用ViewPager的话,代码会比较长,在修改是比较麻烦。


本次工程中的代码只实现了展示了基本的效果,另外有篇写的非常好的博文

Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager

介绍了各种Tab实现的效果和对比。