部分文章來源於:http://www.cnblogs.com/smyhvae/p/3978989.html , 向做者表示感謝html
【正文】java
Android上的界面展現都是經過Activity實現的,Activity實在是太經常使用了。可是Activity也有它的侷限性,一樣的界面在手機上顯示可能很好看,在平板上就未必了,由於平板的屏幕很是大,手機的界面放在平板上可能會有過度被拉長、控件間距過大等狀況。這個時候更好的體驗效果是在Activity中嵌入"小Activity",而後每一個"小Activity"又能夠擁有本身的佈局。所以,咱們今天的主角Fragment登場了。android
1、Fragment初探:app
Fragment是activity的界面中的一部分或一種行爲。你能夠把多個Fragment們組合到一個activity中來建立一個多面界面,而且你能夠在多個activity中重用一個Fragment。你能夠把Fragment認爲模塊化的一段activity,它具備本身的生命週期,接收它本身的事件,並能夠在activity運行時被添加或刪除。eclipse
Fragment不能獨立存在,它必須嵌入到activity中,並且Fragment的生命週期直接受所在的activity的影響。例如:當activity暫停時,它擁有的全部的Fragment們都暫停了,當activity銷燬時,它擁有的全部Fragment們都被銷燬。然而,當activity運行時(在onResume()以後,onPause()以前),你能夠單獨地操做每一個Fragment,好比添加或刪除它們。當你在執行上述針對Fragment的事務時,你能夠將事務添加到一個棧中,這個棧被activity管理,棧中的每一條都是一個Fragment的一次事務。有了這個棧,就能夠反向執行Fragment的事務,這樣就能夠在Fragment級支持「返回」鍵(向後導航)。ide
當向activity中添加一個Fragment時,它須置於ViewGroup控件中,而且需定義Fragment本身的界面。你能夠在layoutxml文件中聲明Fragment,元素爲:<fragment>;也能夠在代碼中建立Fragment,而後把它加入到ViewGroup控件中。然而,Fragment不必定非要放在activity的界面中,它能夠隱藏在後臺爲actvitiy工做。模塊化
設計的哲學:佈局
爲了讓界面能夠在平板上更好地展現,Android在3.0版本引入了Fragment(碎片)功能,經過官方文檔中的這張圖片能夠很明顯地看到Fragment的好處:測試
注:左邊爲平板,右邊爲手持設備。spa
2、Fragment的生命週期:
由於Fragment必須嵌入在Acitivity中使用,因此Fragment的生命週期和它所在的Activity是密切相關的。
若是Activity是暫停狀態,其中全部的Fragment都是暫停狀態;若是Activity是stopped狀態,這個Activity中全部的Fragment都不能被啓動;若是Activity被銷燬,那麼它其中的全部Fragment都會被銷燬。
可是,當Activity在活動狀態,能夠獨立控制Fragment的狀態,好比加上或者移除Fragment。
當這樣進行fragment transaction(轉換)的時候,能夠把fragment放入Activity的back stack中,這樣用戶就能夠進行返回操做。
使用Fragment時,須要繼承Fragment或者Fragment的子類(DialogFragment, ListFragment, PreferenceFragment, WebViewFragment),因此Fragment的代碼看起來和Activity的相似。
每當建立一個Fragment時,首先添加如下三個回調方法:
通常來講,咱們建立一個Fragment的話,都要實現這三個方法
可是Fragment有本身的生命週期,在他的生命週期中有多個方法被調用,下面先將Fragment的生命週期圖展現一下,之後會詳細的介紹:
將Fragment加載到Activity當中有兩種方式:
第一種方式雖然簡單但靈活性不夠。添加Fragment到Activity的佈局文件當中,就等同於將Fragment及其視圖與activity的視圖綁定在一塊兒,且在activity的生命週期過程當中,沒法切換fragment視圖。
第二種方式比較複雜,但也是惟一一種能夠在運行時控制fragment的方式(加載、移除、替換)。
下面將分別介紹一下。
方式一:
首先建立一個Fragment,分爲兩步,建立一個Fragment未來要加載的佈局文件,以後用java代碼建立一個Fragment類
fragment.xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="fragment測試"/> <RatingBar android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="事件點擊"/> </LinearLayout>
FragmentTest.java文件
注:由於咱們的程序是面對Android 4.0以上版本的,因此導入Fragment的包時,選擇第一個:android.app.Fragment
public class FragmentTest extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment,container, false); final Button button = (Button)view.findViewById(R.id.button); final TextView textView = (TextView)view.findViewById(R.id.textView); //Fragment處理本身事件,保持了相對獨立性 button.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { textView.setText("按鈕被點擊"); } }) ; return view ; } @Override public void onPause() { super.onPause(); } }
Activity的佈局文件 activity_main.xml
<RelativeLayout xmlns: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.penglee.fragment_first.MainActivity" > <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:text="@string/hello_world" /> <!-- 必須爲fragment指定id或者tag --> <fragment android:id="@+id/fragment_1" android:name="com.penglee.fragment_first.FragmentTest" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/textView"/> </RelativeLayout>
MainActivity.java 文件
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
運行結果:
方式二:經過java代碼動態的加載Fragment對象
咱們經過一個實例來看看如何使用java代碼動態的加載Fragment,下面的實例的效果是:
咱們將主佈局劃分爲兩部分,右邊一部分使用一個Fragment填充;開始時右邊什麼都沒有,當咱們點擊左邊的Show按鈕以後,右邊就會顯示上圖中的界面
主佈局文件:activity.xml 文件
<LinearLayout xmlns: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:orientation="horizontal"> <LinearLayout android:id="@+id/left" android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" android:background="#00BBBB"> <Button android:id="@+id/show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Show"/> </LinearLayout> <!-- 做爲裝載 Fragment的容器--> <LinearLayout android:id="@+id/right" android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="3" android:background="#EEFFFF"> </LinearLayout> </LinearLayout>
Fragment的佈局文件 fragment_right.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新聞內容"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Show Toast"/> </LinearLayout
Fragment類代碼文件 Right_Fragment.java文件
public class RightFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_right, null) ; Button button = (Button) view.findViewById(R.id.button); button.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { Toast.makeText(getActivity(), "新聞推送", Toast.LENGTH_SHORT).show(); } }); return view ; } }
注意上面的Toast的makeText()方法中的第一個參數,因爲這個參數必須接受一個Context類型的對象,因此咱們只可以使用getActivity
方法類得到加載Fragment的Activity對象
最後是主Activity代碼 MainActivity.java 文件:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button =(Button) findViewById(R.id.show) ; button.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { //步驟一:添加一個FragmentTransaction的實例 FragmentManager fragmentManager =getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); //步驟二:用add()方法加上Fragment的對象rightFragment RightFragment rightFragment = new RightFragment(); //transaction.add(R.id.right, rightFragment,"fragment_right"); transaction.replace(R.id.right, rightFragment); //步驟三:調用commit()方法使得FragmentTransaction實例的改變生效 transaction.commit(); } }); } }
注意:上面的代碼中FragmentTransaction類中加載一個Fragment對象的方法有兩個:
replace(int containerViewId, Fragment fragment, String tag) ;
add(int containerViewId, Fragment fragment, String tag) ;
參數containerViewId:指定裝載Fragment的容器
參數fragment:指定裝載的Fragment對象的Tag,這個Tag和使用<fragment ..../>中指定的id和tag是一個意思都是用來惟一標定一個Fragment對象的標記變量
上面咱們使用的replace方法,若是咱們使用add方法,以後咱們單擊界面左邊的Show按鈕,即不斷地調用add方法會有什麼效果呢?
很是的簡單,由於容器是LinearLayout,那麼天然全部的Fragment的加載時,會縱向排列,固然咱們最好爲上面的每一個Fragment對象一個不一樣的tag標記