1. 程式人生 > >Android基礎_頁面佈局_碎片(Fragment)

Android基礎_頁面佈局_碎片(Fragment)

有些佈局可能在手機上看起來很漂亮,但是拿到螢幕比較大的橫屏平板上面,有些控制元件可能會遭到拉伸,嚴重影響使用者體驗,作為一個合格的開發人員我們應該兼顧這兩種情況,所以在Android3.0之後,Android引入了碎片的概念,它可以讓介面更好的在平板上展示。在Android3.0之前的版本需要引入需要先匯入android-support-v4的jar包才能使用Fragment功能。

1.碎片是什麼?

碎片(Fragment)是一種可以巢狀在活動當中的UI片段,它能使程式更加合理地利用大螢幕控制元件,所有在平板程式中應用廣泛。它和活動類似,可以包含佈局、有自己的生存週期。我們可以把Fragment理解成一個迷你型的活動,但是這個迷你型的活動也有可能和普通的活動一樣大。

何種情況才會應用Fragment呢。就比如Android版的CSDN部落格,我想把我的博文在APP中顯示出來如果不利用Fragment的話,在手機上應該是這樣顯示的(如下圖),Activity01用於顯示文章的標題列表,點選一個標題進入Activity02活動中檢視具體的內容,這個時候如果在Activity01中標題的內容長短不一,極有可能使其顯示不美觀。

             

           Activity01                                       Activity02


利用Fragment的話介面應該是這樣的,我們把上面Activity01、Activity02兩個活動都當做是Fragment,然後把這個兩個Fragment放入到一個活動中去。



2.碎片的簡單用法

我們新建兩個FragmentLeftActivity、FragmentRightActivity碎片,讓它們在MainActivity活動中一左一右。

在繼承Fragment時細心的我們能發現,會有兩個不同包下的Fragment給我們引用,建議用"android.app.Fragment",因為包"android.support.v4.app.Fragment"主要是為了相容低版本,這裡我們用的是Android4.0以上了,所以用"android.app.Fragment"。

FragmentLeftActivity.java

package com.example.fragmenttest;

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

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

}

left_layout.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" >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Button" />

</LinearLayout>

FragmentRightActivity.java
package com.example.fragmenttest;

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

public class FragmentRightActivity extends Fragment{

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


right_layout.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:background="#00ff00"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="This is right fragment"
        android:textSize="20sp" />

</LinearLayout>


MainActivity.java

package com.example.fragmenttest;

import android.app.Activity;
import android.os.Bundle;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

}


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
	android:layout_height="match_parent" 
	android:baselineAligned="false">

    <fragment
        android:id="@+id/xml_leftFragment"
        android:name="com.example.fragmenttest.FragmentLeftActivity"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1"/>
    
    <fragment 
        android:id="@+id/xml_rightFragment"
        android:name="com.example.fragmenttest.FragmentRightActivity"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1"/>

</LinearLayout>


                                                            圖2.1

3.動態新增碎片

在2中我們在活動中的xml佈局檔案中添加了兩個碎片,但是實際程式中這樣靜態地新增是很不實用的。所以我們還可以動態地向活動中新增Fragment。

替換xml中的的Fragment

AnotherRightFragment fragment = new AnotherRightFragment();   //1.建立待操作的碎片例項
FragmentManager fragmentManager = getFragmentManager();       //2.獲取到FragmentManager,在活動中可以直接呼叫getFragmentManager()方法得到
FragmentTransaction transaction = fragmentManager. beginTransaction(); //3.開啟一個事務,通過呼叫beginTransaction()方法開啟
transaction.replace(R.id.right_layout, fragment);         //4.向容器內加入碎片,一般使用replace()方法實現,需要傳入容器的id和待新增碎片的例項
transaction.commit();                                     //5.提交事務,呼叫commit()方法實現</span>

在圖2.1中,原本的右邊的碎片在執行完上面的程式碼後,右邊的碎片變成了AnotherRightFragment的例項,我們按下back鍵發現程式直接退出了,那麼我們建立一個類似於活動返回棧的空間,按下back鍵,是右邊的碎片回到之前的狀態,FragmentTransaction提供了一個addToBackStack()方法,可以用於將一個事務新增到返回棧中。在事務commit()之前,呼叫transcation.addToBackStack(null),它可以接收一個名字用於描述返回棧的狀態,一般傳入null即可。現在重新執行程式,將AnotherRightFragment新增到活動中,然後按下Back鍵,你會發現程式並沒有退出,而是回到了RightFragment介面,再次按下Back鍵程式才會退出。

4.碎片和活動之間的通訊

1) 碎片使用活動中的方法

在每個碎片中都可以通過呼叫getActivity()方法獲取和當前碎片相關聯的活動,比如碎片在MainActivity活動中顯示:

MainActivity activity = (MainActivity) getActivity();

有了例項之後,呼叫便不成問題了。另外當碎片要使用活動的Context物件時,也可以使用getActivity()方法來獲取,因為獲取到的活動本身就是一個Context物件。

2) 活動使用碎片中的方法

為了方便碎片和活動之間的通訊,FragmentManager提供了一個類似於findViewById()的方法,專門用於從佈局檔案中獲取碎片的例項:

FragmentRightActivity fragment = (FragmentRightActivity ) getFragmentManager().findFragmentById(R.id.right_layout);

可以在活動中獲取到碎片的例項。

3) 碎片之間相互呼叫

碎片之間的相互呼叫,其實一個碎片獲取到該活動的例項,再通過該活動獲取到另一個碎片的例項,這樣兩個碎片便可通訊了。

5.碎片的生命週期

碎片的生命週期和活動的生命週期很相似。分為四個狀態

1)執行狀態

當一個碎片是可見的,並且與它相關聯的活動處於執行狀態時,該碎片也處於執行狀態。

2)暫停狀態

當一個活動處於暫停狀態(一個未佔滿螢幕的活動到了返回棧定)時,與它相關聯的可見碎片就處於暫停狀態。

3)停止狀態

當一個活動進入停止狀態時與它相關聯的碎片就進入停止狀態。或者通過呼叫FragmentTransaction的remove()、replace()方法將碎片從活動中移除,但有在事務提交之前呼叫addToBackStack()方法,這時的碎片也會進入到停止狀態。總的來說,進入停止狀態的碎片對使用者來說是完全不可見的,有可能會被系統回收。

4)銷燬狀態

碎片總是依附於活動而存在的,因此當活動被銷燬時,與它相關聯的碎片就會進入到銷燬狀態。或者通過呼叫FragmentTransaction的remove()、replace()方法將碎片從活動中移除,但在事務提交之前並沒有呼叫addToBackStack()方法,這時的碎片也會進入到銷燬狀態。

一部分回撥方法:

1) onAttach()

當碎片和活動建立關聯時呼叫。

2) onCreateView()

為碎片載入佈局時呼叫。

3) onActivityCreated()

確保與碎片相關聯的活動一定已經建立完畢的時候呼叫。

4) onDestroyView()

當與碎片關聯的檢視被移除的時候呼叫。

5) onDetach()

當碎片和活動解除關聯的時候呼叫。


         Android官網的碎片生命週期示意圖

生命週期的理解:

1)當碎片第一次被載入到螢幕上時,會依次執行onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()和onResume()方法。

2)碎片被替換成另一個碎片時,原來的碎片進入停止狀態(呼叫了addToBackStack方法),依次執行onPause()、onStop()和onDestroyView()。

3)碎片被替換成另一個碎片時,原來的碎片進入銷燬狀態(沒有呼叫了addToBackStack方法),依次執行onPause()、onStop()、onDestroyView()、onDestroy()、onDetach()。

4)按鍵back鍵時(呼叫了addToBackStack方法),碎片重新回到執行狀態,onActivityCreated()、onStart()和onResume()。onCreate()和onCreateView()方法並不會執行,因為我們藉助了addToBackStack()方法使得碎片和它的檢視並沒有銷燬。

5)按鍵back鍵時(未呼叫了addToBackStack方法),碎片處於銷燬狀態,依次執行onPause()、onStop()、onDestroyView()、onDestroy()、onDetach()。