Fragment初体验之实现Tab导航

来源:互联网 发布:安卓照片怎么导入mac 编辑:程序博客网 时间:2024/05/16 11:05

记录fragment的博客和资料已经很多很多了,光csdn上我就看了郭lin和鸿洋大神的blog,都写的很好。我写这篇关于fragment博客的目的是想从一个初学者的角度去谈谈我学习fragment的过程和体会以及遇到的牵扯到的相关问题,另一方面也当成自己的电子笔记,希望对其他初学者能有所帮助。




一、fragment简介



简单谈一下我对fragment的理解,由于手机屏幕较小,一个Activity能放的东西是有限的,比如一个列表一般就占满了整个屏幕,再查看详情则只能通过跳转到新的Activity去实现。而平板电脑的出现解决了屏幕小的问题,那么需求也就暴露了出来,平板的宽屏幕可以展示的东西更多了,而且在一个Activity放置过多的组件也不易于管理,所以fragment出现了,它可以代表Activity的子模块,并且有自己独立的生命周期。


在web开发中有一种经典的页面模型,上左右分三块,一般上面占满屏幕宽度,放Logo之类的,左边是树状菜单,而右边是用于展示菜单的内容,点击菜单、刷新右边的页面,类似于这样:



在web中实现这种布局很简单,我们都知道使用框架,比如frameset或者iframe,分别写3个子html页面用于显示上面的3块内容,最后通过<iframe>或者<frameset>标签把它们放在一个容器html页面中即可,通过点击左侧菜单的超链接来改变右边的内容页面。


其实Android也是类似的,如果要在平板电脑上实现上面的效果,那就需要使用fragment来完成了,上面可能是一个titlebar或者是一个放TextView的fragment,左边可能是一个放ListView的fragment,而右边也就是放内容的fragment,没错,fragment相当于frameset或iframe,它只是一个容器。还有一点很重要,就是fragment必须被“嵌入”Activity中使用,并且它有自己的生命周期和响应事件,但fragment的生命周期直接被其所属的activity的生命周期控制



二、创建fragment




与创建Activity类似,创建一个fragment首先要继承android.app.Fragment,并且要重写onCreatView方法,为什么要重写这个方法,因为上面说了fragment只是容器,那么只有装了东西这个容器才完整,这个所谓的“东西”也就是各种各样的组件了,onCreatView方法的返回值是View,这个View也就是fragment所要显示的View,可以参照官方文档:



这句话说的很清楚了,为fragment提供一个布局的话,你必须实现onCreatView()这个回调方法。

清楚了这两点,那么我们写一个简单的自定义Fragment类。

[java] view plaincopy
  1. package com.xw.fragment;  
  2.   
  3. import android.app.Fragment;  
  4. import android.os.Bundle;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8.   
  9. public class MyFragment1 extends Fragment {  
  10.   
  11.     @Override  
  12.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  13.             Bundle savedInstanceState) {  
  14.         View view = inflater.inflate(  
  15.                 com.example.fragmentdemo.R.layout.fragment1, container, false);  
  16.         return view;  
  17.     }  
  18. }  
可以看到是通过LayoutInflater的inflate方法去加载布局的,而这个布局也就是这个fragment所要显示的布局。关于inflate方法初学者可能不是很清楚,其实我本人也不是很清楚,以前实例化布局我都是用setContentView这个方法,那这个inflate方法和setContentView方法又有什么区别和联系呢?


从表面上看:

setContentView方法没有返回值,并且是Activity的一个实例方法。


那么既然没有返回值,并且在当前的Activity的中被调用,那么可想而知,那么这个方法应该就是为当前的Activity加载布局了,而fragment里面并没有setContentView方法,所以开发fragment的时候我们没有可选择性,目前我们只需要知道inflate方法就是用来实例化布局的就可以了,关于具体的细节和原理我们在后续的blog中再做记录。


对了,为了看到后面的简单效果再show一下fragment1.xml,很简单,只是一个红色的TextView:

[html] view plaincopy
  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.     android:padding="10dp"  
  7.     >  
  8.   
  9.     <TextView  
  10.         android:layout_width="100dp"  
  11.         android:layout_height="100dp"  
  12.         android:background="#FF0000"   
  13.         android:text="fragment one"  
  14.         android:gravity="center"  
  15.         />  
  16.   
  17. </LinearLayout>  



三、在Activity中显示Fragment



上面我们已经知道了如何创建一个fragment,但是fragment终究还是要被“嵌入”到Activity中才能使用的,那么我们就具体看一下如何在Activity中引用fragment,其实就是如何在activity的布局文件中引入fragment

[html] view plaincopy
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:padding="10dp"  
  6.     tools:context="com.xw.activity.MainActivity" >  
  7.      
  8.     <fragment   
  9.         android:id="@+id/fm_fragment1"  
  10.         android:name="com.xw.fragment.MyFragment1"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="match_parent"  
  13.         />  
  14.      
  15. </LinearLayout>  

显而易见的,是通过<fragment>的android:name属性来引入fragment


Activity的代码不变,依然是setContentView(R.layout.activity_main.xml),最后运行一下看看效果:




这样就完成了在Activity中展示一个fragment,这样的效果也许看不出什么,稍候我会做一个典型的fragment的应用的例子,也就是我们经常会用到的Tab导航。



四、常用方法和API



在fragment中获取它所在的Activity:Activity activity=getActivity();

在Activity中获取fragment:getFragmentManager().findFragmentById()或findFragmentByTag();

在上面可以看到getFragmentManager()方法,它返回的是一个FragmentManager对象:

FragmentManager fragmentManager=getFragmentManager();

如果要添加、删除或替换fragment,那么就需要FragmentTransaction对象的一系列方法来处理了:

FragmentTransaction ftx=fragmentManager.beginTransaction();

向Activity中添加一个fragment:

ftx.add(Fragment fragment,String tag);

从Activity中移除一个fragment:

ftx.remove(Fragment fragment);

使用一个fragment替换当前的fragment:

ftx.replace(int containerViewId,Fragment fragment);

隐藏当前的fragment:

ftx.hide(Fragment fragment);

显示之前隐藏的fragment:

ftx.show(Fragment fragment);


FragmentTransaction与DatabaseTransaction类似,后者一般代表对底层数据库的多个更新操作,而前者表示Activity对Fragment执行的多个改变操作,相同的是,最后都要调用commit()方法进行提交操作。



五、Tab导航的例子



其实文字的东西也没啥写的,无非就是那点东西,下面通过一个实例来练习一下fragment的具体用法,这个例子就是经常会用到的Tab导航。


Layout代码(activity_main.xml):


[html] view plaincopy
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="@drawable/bg_main_day"  
  6.     android:orientation="vertical"  
  7.     tools:context=".MainActivity" >  
  8.   
  9.     <RadioGroup  
  10.         android:id="@+id/rg_select_main"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="45dp"  
  13.         android:gravity="center_vertical"  
  14.         android:orientation="horizontal" >  
  15.   
  16.         <RadioButton  
  17.             android:id="@+id/rb1"  
  18.             style="@style/SelectTextView"  
  19.             android:layout_width="match_parent"  
  20.             android:layout_height="wrap_content"  
  21.             android:layout_weight="1.0"  
  22.             android:background="@drawable/iv_selectbar_selector"  
  23.             android:button="@null"  
  24.             android:gravity="center"  
  25.             android:text="当前推荐" />  
  26.   
  27.         <RadioButton  
  28.             android:id="@+id/rb2"  
  29.             style="@style/SelectTextView"  
  30.             android:layout_width="match_parent"  
  31.             android:layout_height="wrap_content"  
  32.             android:layout_weight="1.0"  
  33.             android:background="@drawable/iv_selectbar_selector"  
  34.             android:button="@null"  
  35.             android:gravity="center"  
  36.             android:text="景点" />  
  37.   
  38.         <RadioButton  
  39.             android:id="@+id/rb3"  
  40.             style="@style/SelectTextView"  
  41.             android:layout_width="match_parent"  
  42.             android:layout_height="wrap_content"  
  43.             android:layout_weight="1.0"  
  44.             android:background="@drawable/iv_selectbar_selector"  
  45.             android:button="@null"  
  46.             android:gravity="center"  
  47.             android:text="美食" />  
  48.   
  49.         <RadioButton  
  50.             android:id="@+id/rb4"  
  51.             style="@style/SelectTextView"  
  52.             android:layout_width="match_parent"  
  53.             android:layout_height="wrap_content"  
  54.             android:layout_weight="1.0"  
  55.             android:background="@drawable/iv_selectbar_selector"  
  56.             android:button="@null"  
  57.             android:gravity="center"  
  58.             android:text="文化" />  
  59.   
  60.         <RadioButton  
  61.             android:id="@+id/rb5"  
  62.             style="@style/SelectTextView"  
  63.             android:layout_width="match_parent"  
  64.             android:layout_height="wrap_content"  
  65.             android:layout_weight="1.0"  
  66.             android:background="@drawable/iv_selectbar_selector"  
  67.             android:button="@null"  
  68.             android:gravity="center"  
  69.             android:text="娱乐" />  
  70.     </RadioGroup>  
  71.   
  72.     <FrameLayout  
  73.         android:id="@+id/main_frame"  
  74.         android:layout_width="match_parent"  
  75.         android:layout_height="match_parent" >  
  76.     </FrameLayout>  
  77.   
  78. </LinearLayout>  

Activity代码:

[java] view plaincopy
  1. package com.xw.activity;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.FragmentTransaction;  
  5. import android.os.Bundle;  
  6. import android.widget.RadioButton;  
  7. import android.widget.RadioGroup;  
  8. import android.widget.RadioGroup.OnCheckedChangeListener;  
  9.   
  10. import com.example.fragmenttabdemo.R;  
  11. import com.xw.fragment.FragmentFive;  
  12. import com.xw.fragment.FragmentFour;  
  13. import com.xw.fragment.FragmentOne;  
  14. import com.xw.fragment.FragmentThree;  
  15. import com.xw.fragment.FragmentTwo;  
  16.   
  17. public class MainActivity extends Activity implements OnCheckedChangeListener {  
  18.   
  19.     private RadioGroup rg;  
  20.     private RadioButton rb;  
  21.   
  22.     private FragmentOne fone;  
  23.     private FragmentTwo ftwo;  
  24.     private FragmentThree fthree;  
  25.     private FragmentFour ffour;  
  26.     private FragmentFive ffive;  
  27.   
  28.     @Override  
  29.     protected void onCreate(Bundle savedInstanceState) {  
  30.         super.onCreate(savedInstanceState);  
  31.         setContentView(R.layout.activity_main);  
  32.   
  33.         setupView();  
  34.         addListener();  
  35.     }  
  36.   
  37.     private void setupView() {  
  38.         rg = (RadioGroup) findViewById(R.id.rg_select_main);  
  39.         rb = (RadioButton) findViewById(R.id.rb1);  
  40.   
  41.         // 实例化fragment  
  42.         fone = new FragmentOne();  
  43.         ftwo = new FragmentTwo();  
  44.         fthree = new FragmentThree();  
  45.         ffour = new FragmentFour();  
  46.         ffive = new FragmentFive();  
  47.   
  48.         // 初始化activity显示的fragment  
  49.         FragmentTransaction ftx = getFragmentManager().beginTransaction();  
  50.         ftx.add(R.id.main_frame, fone);  
  51.         ftx.commit();  
  52.   
  53.         rb.setChecked(true); // 初始化选中当前推荐  
  54.     }  
  55.   
  56.     private void addListener() {  
  57.         rg.setOnCheckedChangeListener(this);  
  58.     }  
  59.   
  60.     @Override  
  61.     public void onCheckedChanged(RadioGroup group, int checkedId) {  
  62.         FragmentTransaction ftx = getFragmentManager().beginTransaction();  
  63.         switch (checkedId) {  
  64.         case R.id.rb1:  
  65.             ftx.replace(R.id.main_frame, fone);  
  66.             break;  
  67.         case R.id.rb2:  
  68.             ftx.replace(R.id.main_frame, ftwo);  
  69.             break;  
  70.         case R.id.rb3:  
  71.             ftx.replace(R.id.main_frame, fthree);  
  72.             break;  
  73.         case R.id.rb4:  
  74.             ftx.replace(R.id.main_frame, ffour);  
  75.             break;  
  76.         case R.id.rb5:  
  77.             ftx.replace(R.id.main_frame, ffive);  
  78.             break;  
  79.         default:  
  80.             break;  
  81.         }  
  82.         ftx.commit();  
  83.     }  
  84.   
  85. }  

 

Fragment的代码就不贴了,都很简单,和上面基本一样,下面看看运行效果:



很简单吧!通过点击不同的radiobutton,根据id去判断并替换containerView中的组件,这应该是fragment最简单的一种应用,也许还有潜在的bug和不合理的地方,欢迎各位批评指正。



六、总结



本篇记录了我认识fragment的过程,也许只是一个最简单的demo,但对于我来说也算是一点一滴的进步,关于fragment的生命周期、back stack、与activity之间的通信、fragment管理与fragment事务等等暂且还没有去详细了解,只是尽快熟悉了API和用法,然后立刻上手敲一个小demo,不知道这种学习方法对不对,但是我更倾向于这样,先会用,再研究原理,因为做出东西就会有成就感,为继续学习提供了动力。一般菜鸟废话都比较多,呵呵。我还是会继续努力的,要抓紧了,在Android上不能耽误太多时间,要学的东西还有很多很多,加油。

0 0