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()。