Fragments(片元)
譯者署名: shadowl
譯者鏈接:blueclue.cnblogs.com
版本:Android 4.0 r1
片元(Fragments)
A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a "sub activity" that you can reuse in different activities).
Fragment表現(xiàn)Activity中用戶界面的一個行為或者是一部分。你可以在一個單獨的activity上把多個fragment組合成為一個多區(qū)域的UI,并且可以在多個activity中再使用。你可以認(rèn)為fragment是activity的一個模塊零件,它有自己的生命周期,接收它自己的輸入事件,并且可以在activity運行時添加或者刪除。
A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the BACK button.
Fragment必須總是被嵌入到一個activity之中,并且fragment的生命周期直接受其宿主activity的生命周期的影響。例如,一旦activity被暫停,它里面所有的fragment也被暫停,一旦activity被銷毀,它里面所有的fragment也被銷毀。然而,當(dāng)activity正在運行時(處于resumed的生命周期狀態(tài)),你可以單獨的操控每個fragment,比如添加或者刪除。當(dāng)你執(zhí)行這樣一項事務(wù)時,可以將它添加到后臺的一個棧中,這個棧由activity管理著——activity里面的每個后臺棧內(nèi)容實體是fragment發(fā)生過的一條事務(wù)記錄。這個后臺棧允許用戶通過按BACK鍵回退一項fragment事務(wù)(往后導(dǎo)航)。
When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity's view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a <fragment> element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.
當(dāng)你添加一個fragment作為某個activity布局的一部分時,它就存在于這個activity視圖體系內(nèi)部的ViewGroup之中,并且定義了它自己的視圖布局。你可以通過在activity布局文件中聲明fragment,用<fragment>元素把fragment插入到activity的布局中,或者是用應(yīng)用程序源碼將它添加到一個存在的ViewGroup中。然而,fragment并不是一個定要作為activity布局的一部分;fragment也可以為activity隱身工作。
This document describes how to build your application to use fragments, including how fragments can maintain their state when added to the activity's back stack, share events with the activity and other fragments in the activity, contribute to the activity's action bar, and more.
這份文檔描述了如何使用fragment來創(chuàng)建你的應(yīng)用程序,包括fragment在添加到后臺棧時如何維護他們的狀態(tài),如何同activity和其他同屬于該activity的fragment們共享事件,構(gòu)建到activity的動作槽(action bar)中去,等等。
設(shè)計原理(Design Philosophy)
Android introduced fragments in Android 3.0 (API level 11), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet's screen is much larger than that of a handset, there's more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity's appearance at runtime and preserve those changes in a back stack that's managed by the activity.
Android在3.0這個版本中(API Level “Honeycomb”)引入了fragment的概念,主要是支持在大屏幕上更為動態(tài)和靈活的UI設(shè)計,比方說平板電腦。由于平板電腦的屏幕要比手持電話的大許多,這樣就有更多的空間去組合和交換UI組件。有了fragment,你可以不必去管理視圖體系的復(fù)雜變化。通過將activity的布局分割成若干個fragment,可以在運行時編輯activity的呈現(xiàn),并且那些變化會被保存在由activity管理的后臺棧里面。
For example, a news application can use one fragment to show a list of articles on the left and another fragment to display an article on the right—both fragments appear in one activity, side by side, and each fragment has its own set of lifecycle callback methods and handle their own user input events. Thus, instead of using one activity to select an article and another activity to read the article, the user can select an article and read it all within the same activity, as illustrated in the tablet layout in figure 1.
例如,新聞應(yīng)用程序?qū)⒁粋€fragment放在左邊顯示文章列表,在右邊用另一個fragment來顯示一篇文章——兩個fragment在同一個activity中并排著,并且每個fragment都有其自己的生命周期回調(diào)方法序列用以處理各自的用戶輸入事件。因此,用戶可以在同一個activity中選擇和閱讀文章,而不是在一個activity中選擇,在另一個activity中閱讀,如圖1所示。
You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity.
應(yīng)該將每一個fragment設(shè)計為模塊化的和可復(fù)用化的activity組件。也就是說,你可以在多個activity中引用同一個fragment,因為fragment定義了它自己的布局,并且使用它本身生命周期回調(diào)的行為。這點尤為重要,因為它讓你能夠改變fragment組合以滿足不同的屏幕尺寸。在設(shè)計同時支持平板電腦和手機的應(yīng)用時,通過不同的布局配置可以復(fù)用fragments,基于可使用的屏幕空間優(yōu)化用戶體驗。例如,在手機上,當(dāng)同一個activity不能容納更多的fragment時,可能需要通過分離fragments提供一個單區(qū)域的界面。

Figure 1. An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.
圖1:示例說明如何用兩個fragment在一個activity中組合兩個UI模塊布局的平板電腦模式,取代界面分離的手機模式。
For example—to continue with the news application example—the application can embed two fragments in Activity A, when running on a tablet-sized device. However, on a handset-sized screen, there's not be enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the second fragment to read the article. Thus, the application supports both tablets and handsets by reusing fragments in different combinations, as illustrated in figure 1.
例如——還是以那個新聞應(yīng)用程序為例——當(dāng)程序運行在平板尺寸屏幕設(shè)備上時,可以在Activity A中嵌入兩個fragment。但是,當(dāng)運行在手機尺寸屏幕上,就沒有足夠的空間容納兩個fragment了,因此Activity A只能引用包含文章列表的fragment,在當(dāng)用戶選擇一篇文章時,可以啟動Activity B,它包含了用來閱讀文章的第二個fragment。這樣,應(yīng)用程序通過以不同組合的復(fù)用fragments支持了平板電腦和手機,如圖1所示。
For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.
對于不同的屏幕配置以不同的fragment組合設(shè)計應(yīng)用程序的更多相關(guān)資料,參考手冊的支持平板電腦和手機的相關(guān)部分。
創(chuàng)建片元(Creating a Fragment)
To create a fragment, you must create a subclass of Fragment (or an existing subclass of it). The Fragment class has code that looks a lot like an Activity. It contains callback methods similar to an activity, such as onCreate(), onStart(), onPause(), and onStop(). In fact, if you're converting an existing Android application to use fragments, you might simply move code from your activity's callback methods into the respective callback methods of your fragment.
要創(chuàng)建一個fragment,必須創(chuàng)建一個fragment的子類(或是繼承自它的子類)。fragment類的代碼看起來很像activity。它與activity一樣都有回調(diào)函數(shù),例如onCreate(),onStart(),onPause(),和
onStop()。事實上,如果你正在將一個現(xiàn)成的Android應(yīng)用轉(zhuǎn)而使用Fragment來實現(xiàn),可以簡單的將代碼從activity的回調(diào)函數(shù)移植到各自的fragment回調(diào)函數(shù)中。
Usually, you should implement at least the following lifecycle methods:
一般情況下,你至少需要實現(xiàn)以下幾個生命周期方法:
onCreate()
The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
在創(chuàng)建fragment時系統(tǒng)會調(diào)用此方法。在實現(xiàn)代碼中,你可以初始化想要在fragment中保持的那些必要組件,當(dāng)fragment處于暫?;蛘咄V?fàn)顟B(tài)之后可重新啟用它們。
onCreateView()
The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
在第一次為fragment繪制用戶界面時系統(tǒng)會調(diào)用此方法。為fragment繪制用戶界面,這個函數(shù)必須要返回所繪出的fragment的根View。如果fragment沒有用戶界面可以返回空。
onPause()
The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).
系統(tǒng)回調(diào)用該函數(shù)作為用戶離開fragment的第一個預(yù)兆(盡管這并不總意味著fragment被銷毀)。在當(dāng)前用戶會話結(jié)束之前,通常要在這里提交任何應(yīng)該持久化的變化(因為用戶可能不再返回)。
Most applications should implement at least these three methods for every fragment, but there are several other callback methods you should also use to handle various stages of the fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section about Handling the Fragment Lifecycle.
大部分應(yīng)用程序都應(yīng)該至少為每個fragment實現(xiàn)這三個方法,但是還有許多其他用以操縱fragment生命周期中各個階段的回調(diào)函數(shù)。所有生命周期中的回調(diào)函數(shù)在操縱fragment生命周期一節(jié)中稍后再做討論。
There are also a few subclasses that you might want to extend, instead of the base Fragment class:
除了基類fragment,這里還有幾個你可能會繼承的子類:
DialogFragment
Displays a floating dialog. Using this class to create a dialog is a good alternative to using the dialog helper methods in the Activity class, because you can incorporate a fragment dialog into the back stack of fragments managed by the activity, allowing the user to return to a dismissed fragment.
顯示一個浮動的對話框。使用這個類創(chuàng)建對話框是使用Activity類對話框工具方法之外的另一個不錯的選擇,因為你可以把fragment對話框并入到由activity管理的fragments后臺棧中,允許用戶返回到一個已經(jīng)摒棄的fragment。
ListFragment
Displays a list of items that are managed by an adapter (such as a SimpleCursorAdapter), similar to ListActivity. It provides several methods for managing a list view, such as the onListItemClick() callback to handle click events.
顯示一個由適配器管理的條目列表(例如SimpleCursorAdapter),類似于ListActivity。并且提供了許多管理列表視圖的函數(shù),例如處理點擊事件的onListItemClick()回調(diào)函數(shù)。
PreferenceFragment
Displays a hierarchy of Preference objects as a list, similar to PreferenceActivity. This is useful when creating a "settings" activity for your application.
顯示一個Preference對象的體系結(jié)構(gòu)列表,類似于preferenceActivity。這在為應(yīng)用程序創(chuàng)建“設(shè)置”activity時是很實用的。
添加用戶界面(Adding a user interface)
A fragment is usually used as part of an activity's user interface and contributes its own layout to the activity.
To provide a layout for a fragment, you must implement the onCreateView() callback method, which the Android system calls when it's time for the fragment to draw its layout. Your implementation of this method must return a View that is the root of your fragment's layout.
Note: If your fragment is a subclass of ListFragment, the default implementation returns a ListView from onCreateView(), so you don't need to implement it.
To return a layout from onCreateView(), you can inflate it from a layout resource defined in XML. To help you do so, onCreateView() provides a LayoutInflater object.
fragment常被用作activity用戶界面的一部分,并且將本身的布局構(gòu)建到activity中去。
為了給fragment提供一個布局,你必須實現(xiàn)onCreateView()回調(diào)函數(shù),在繪制fragment布局時Android系統(tǒng)會調(diào)用它。實現(xiàn)這個函數(shù)時需要返回fragment所屬的根View。
注意:如果你的fragment時ListFragment的子類,默認(rèn)實現(xiàn)從onCreateView()返回一個ListView,所以你不需要實現(xiàn)它。
為了從onCreateView()返回一個布局,你可以從layout resource定義的XML文件inflate它。為了便于你這樣做,onCreateView()提供一個LayoutInflater對象。
For example, here's a subclass of Fragment that loads a layout from the example_fragment.xml file:
例如,下面是一個fragment子類,它的布局從example_fragment.xml載入的:
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
The container parameter passed to onCreateView() is the parent ViewGroup (from the activity's layout) in which your fragment layout will be inserted. The savedInstanceState parameter is a Bundle that provides data about the previous instance of the fragment, if the fragment is being resumed (restoring state is discussed more in the section about Handling the Fragment Lifecycle).
The inflate() method takes three arguments:
The resource ID of the layout you want to inflate.
The ViewGroup to be the parent of the inflated layout. Passing the container is important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it's going.
A boolean indicating whether the inflated layout should be attached to the ViewGroup (the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into the container—passing true would create a redundant view group in the final layout.)
傳入onCreateView()的參數(shù)container 是你的frament布局將要被插入的父ViewGroup(來自activity的布局)。如果fragment處于resumed狀態(tài)(恢復(fù)狀態(tài)在操縱fragment生命周期一節(jié)中將作更多討論),參數(shù)savedInstanceState是屬于Bundle類,它提供了fragment之前實例的相關(guān)數(shù)據(jù)。
inflate()函數(shù)需要以下三個參數(shù):
要inflate的布局的資源ID。
被inflate的布局的父ViewGroup。傳入container很重要,這是為了讓系統(tǒng)將布局參數(shù)應(yīng)用到被inflate的布局的根view中去,由其將要嵌入的父view指定。
一個布爾值,表明在inflate期間被infalte的布局是否應(yīng)該附上ViewGroup(第二個參數(shù))。(在這個例子中傳入的是false,因為系統(tǒng)已經(jīng)將被inflate的布局插入到容器中(container)——傳入true會在最終的布局里創(chuàng)建一個多余的ViewGroup。)
Now you've seen how to create a fragment that provides a layout. Next, you need to add the fragment to your activity.
現(xiàn)在你已經(jīng)知道了如何創(chuàng)建一個有布局的fragment。下一步,則需要將fragment添加到activity中。
將fragment添加到activity之中(Adding a fragment to an activity)
Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part of the activity's overall view hierarchy. There are two ways you can add a fragment to the activity layout:
通常,fragment構(gòu)建了其宿主activity的部分界面,它被作為activity全部視圖層次體系的一部分被嵌入進去。在acitivity布局中添加fragment有兩種方法:
在activity的布局文件里聲明fragment
In this case, you can specify layout properties for the fragment as if it were a view. For example, here's the layout file for an activity with two fragments:
像這樣,你可以像為view一樣為fragment指定布局屬性。例如,下面含有兩個fragment的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas./apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
The android:name attribute in the <fragment> specifies the Fragment class to instantiate in the layout.
When the system creates this activity layout, it instantiates each fragment specified in the layout and calls the onCreateView() method for each one, to retrieve each fragment's layout. The system inserts the View returned by the fragment directly in place of the <fragment> element.
<fragment>中的android:name 屬性指定了布局中實例化的Fragment類。
當(dāng)系統(tǒng)創(chuàng)建activity布局時,它實例化了布局文件中指定的每一個fragment,并為它們調(diào)用onCreateView()函數(shù),以獲取每一個fragment的布局。系統(tǒng)直接在<fragment>元素的位置插入fragment返回的View。
Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:
Supply the android:id attribute with a unique ID.
Supply the android:tag attribute with a unique string.
If you provide neither of the previous two, the system uses the ID of the container view.
注意:每個fragment都需要一個唯一的標(biāo)識,如果重啟activity,系統(tǒng)可用來恢復(fù)fragment(并且可用來捕捉fragment的事務(wù)處理,例如移除)。為fragment提供ID有三種方法:
用android:id屬性提供一個唯一的標(biāo)識。
用android:tag屬性提供一個唯一的字符串。
如果上述兩個屬性都沒有,系統(tǒng)會使用其容器視圖(view)的ID。
Or, programmatically add the fragment to an existing ViewGroup.
或者,通過編碼將fragment添加到已存在的ViewGroup中。
At any time while your activity is running, you can add fragments to your activity layout. You simply need to specify a ViewGroup in which to place the fragment.
To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction. You can get an instance of FragmentTransaction from your Activity like this:
在activity運行的任何時候,你都可以將fragment添加到activity布局中。你僅需要簡單指定用來放置fragment的ViewGroup。
你應(yīng)當(dāng)使用FragmentTransaction的API來對activity中的fragment進行操作(例如添加,移除,或者替換fragment)。你可以像下面這樣從Activity中取得FragmentTransaction的實例:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
You can then add a fragment using the add() method, specifying the fragment to add and the view in which to insert it. For example:
可以用add()函數(shù)添加fragment,并指定要添加的fragment以及要將其插入到哪個視圖(view)之中:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
The first argument passed to add() is the ViewGroup in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.
Once you've made your changes with FragmentTransaction, you must call commit() for the changes to take effect.
傳入add()函數(shù)的第一個參數(shù)是fragment被放置的ViewGroup,它由資源ID(resource ID)指定,第二個參數(shù)就是要添加的fragment。
一旦通過FragmentTransaction 做了更改,都應(yīng)當(dāng)使用commit()使變化生效。
添加無界面的fragment(Adding a fragment without a UI)
The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.
To add a fragment without a UI, add the fragment from the activity using add(Fragment, String) (supplying a unique string "tag" for the fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method.
Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag().
For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java sample.
上面的例子是如何將fragment添加到activity中去,目的是提供一個用戶界面。然而,也可以使用fragment為activity提供后臺動作,卻不呈現(xiàn)多余的用戶界面。
想要添加沒有界面的fragment ,可以使用add(Fragment, String)(為fragment提供一個唯一的字符串“tag”,而不是視圖(view)ID)。這樣添加了fragment,但是,因為還沒有關(guān)聯(lián)到activity布局中的視圖(view) ,收不到onCreateView()的調(diào)用。所以不需要實現(xiàn)這個方法。
為無界面fragment提供字符串標(biāo)簽并不是專門針對無界面fragment的——也可以為有界面fragment提供字符串標(biāo)簽——但是對于無界面fragment,字符串標(biāo)簽是唯一識別它的方法。如果之后想從activity中取到fragment,需要使用findFragmentByTag()。
activity使用fragment在后臺運行可參考例子FragmentRetainInstance.java。
管理fragment(Managing Fragments)
To manage the fragments in your activity, you need to use FragmentManager. To get it, call getFragmentManager() from your activity.
Some things that you can do with FragmentManager include:
Get fragments that exist in the activity, with findFragmentById() (for fragments that provide a UI in the activity layout) or findFragmentByTag() (for fragments that do or don't provide a UI).
Pop fragments off the back stack, with popBackStack() (simulating a BACK command by the user).
Register a listener for changes to the back stack, with addOnBackStackChangedListener().
For more information about these methods and others, refer to the FragmentManager class documentation.
As demonstrated in the previous section, you can also use FragmentManager to open a FragmentTransaction, which allows you to perform transactions, such as add and remove fragments.
想要管理activity中的fragment,可以使用FragmentManager??梢酝ㄟ^在activity中調(diào)用getFragmentManager()獲得。
使用FragmentManager 可以做如下事情,包括:
使用findFragmentById()(用于在activity布局中提供有界面的fragment)或者findFragmentByTag()獲取activity中存在的fragment(用于有界面或者沒有界面的fragment)。
使用popBackStack()(模仿用戶的BACK命令)從后臺棧彈出fragment。
使用addOnBackStackChangedListener()注冊一個監(jiān)聽后臺棧變化的監(jiān)聽器。
關(guān)于這些函數(shù)和其它的更多信息,可參考FragmentManager 類文檔。
處理fragment事務(wù)(Performing Fragment Transactions)
A great feature about using fragments in your activity is the ability to add, remove, replace, and perform other actions with them, in response to user interaction. Each set of changes that you commit to the activity is called a transaction and you can perform one using APIs in FragmentTransaction. You can also save each transaction to a back stack managed by the activity, allowing the user to navigate backward through the fragment changes (similar to navigating backward through activities).
You can acquire an instance of FragmentTransaction from the FragmentManager like this:
在activity中使用fragment的一大特點是具有添加、刪除、替換,和執(zhí)行其它動作的能力,以響應(yīng)用戶的互動。提交給activity的每一系列變化被稱為事務(wù),并且可以用FragmentTransaction 中的APIs處理。你也可以將每一個事務(wù)保存在由activity管理的后臺棧中,并且允許用戶導(dǎo)航回退fragment變更(類似于activity的導(dǎo)航回退)。
你可以從 FragmentManager 中獲取FragmentTransaction 實例,像這樣:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Each transaction is a set of changes that you want to perform at the same time. You can set up all the changes you want to perform for a given transaction using methods such as add(), remove(), and replace(). Then, to apply the transaction to the activity, you must call commit().
Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the BACK key.
For example, here's how you can replace one fragment with another, and preserve the previous state in the back stack:
每項事務(wù)是在同一時間內(nèi)要執(zhí)行的一系列的變更。你可以為一個給定的事務(wù)用相關(guān)方法設(shè)置想要執(zhí)行的所有變化,例如add(),remove(),和replace()。然后,用commit()將事務(wù)提交給activity。
然而,在調(diào)用commit()之前,為了將事務(wù)添加到fragment事務(wù)后臺棧中,你可能會想調(diào)用addToBackStatck()。這個后臺棧由activity管理,并且允許用戶通過按BACK鍵回退到前一個fragment狀態(tài)。
舉個例子,下面的代碼是如何使用另一個fragment代替一個fragment,并且將之前的狀態(tài)保留在后臺棧中:
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
In this example, newFragment replaces whatever fragment (if any) is currently in the layout container identified by the R.id.fragment_container ID. By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the BACK key.
If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the BACK key will reverse them all together.
在這個例子中,newFragment替換了當(dāng)前在布局容器中用R.id.fragment_container標(biāo)識的所有的fragment(如果有的話),替代的事務(wù)被保存在后臺棧中,因此用戶可以回退該事務(wù),可通過按BACK鍵還原之前的fragment。
如果添加多個變更事務(wù)(例如另一個add()或者remove())并調(diào)用addToBackStack(),那么在調(diào)用commit()之前的所有應(yīng)用的變更被作為一個單獨的事務(wù)添加到后臺棧中,并且BACK鍵可以將它們一起回退。
The order in which you add changes to a FragmentTransaction doesn't matter, except:
You must call commit() last
If you're adding multiple fragments to the same container, then the order in which you add them determines the order they appear in the view hierarchy
If you do not call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.
Tip: For each fragment transaction, you can apply a transition animation, by calling setTransition() before you commit.
Calling commit() does not perform the transaction immediately. Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon as the thread is able to do so. If necessary, however, you may call executePendingTransactions() from your UI thread to immediately execute transactions submitted by commit(). Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads.
Caution: You can commit a transaction using commit() only prior to the activity saving its state (when the user leaves the activity). If you attempt to commit after that point, an exception will be thrown. This is because the state after the commit can be lost if the activity needs to be restored. For situations in which its okay that you lose the commit, use commitAllowingStateLoss().
將變更添加到FragmentTransaction中的順序注意以下兩點:
必須要在最后調(diào)用commit()
如果你正將多個fragment添加到同一個容器中,那么添加順序決定了它們在視圖層次(view hierarchy)里顯示的順序。
在執(zhí)行刪除fragment事務(wù)時,如果沒有調(diào)用addToBackStack(),那么事務(wù)一提交fragment就會被銷毀,而且用戶也無法回退它。然而,當(dāng)移除一個fragment時,如果調(diào)用了addToBackStack(),那么之后fragment會被停止,如果用戶回退,它將被恢復(fù)過來。
提示:對于每一個fragment事務(wù),在提交之前通過調(diào)用setTransition()來應(yīng)用一系列事務(wù)動作。.
調(diào)用commit()并不立刻執(zhí)行事務(wù),相反,而是采取預(yù)約方式,一旦activity的界面線程(主線程)準(zhǔn)備好便可運行起來。然而,如果有必要的話,你可以從界面線程調(diào)用executePendingTransations()立即執(zhí)行由commit()提交的事務(wù)。但這樣做,通常是沒有必要的,除非其它線程的工作依賴與該項事務(wù)。
警告:只能在activity保存狀態(tài)(當(dāng)用戶離開activity時)之前用commit()提交事務(wù)。如果你嘗試在那時之后提交,會拋出一個異常。這是因為如果activity需要被恢復(fù),提交后的狀態(tài)會被丟失。對于這類丟失提交的情況,可使用commitAllowingStateLoss()
與activity通訊(Communicating with the Activity)
Although a Fragment is implemented as an object that's independent from an Activity and can be used inside multiple activities, a given instance of a fragment is directly tied to the activity that contains it.
Specifically, the fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:
盡管Fragment被實現(xiàn)為一個對象,它獨立于Activity并可以在多個Activity中使用,一個給定的fragment實例直接被捆綁在包含它的Activity中。
特別是,fragment可以通過getActivity()函數(shù)訪問Activity,并且很容易的執(zhí)行類似于查找activity布局中的視圖的任務(wù):
View listView = getActivity().findViewById(R.id.list);
Likewise, your activity can call methods in the fragment by acquiring a reference to the Fragment from FragmentManager, using findFragmentById() or findFragmentByTag(). For example::
同樣的,activity能夠調(diào)用fragment的函數(shù)findFragmentById()或者findFragmentByTag(),從FragmentManager中獲取Fragment的索引,例如:
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
創(chuàng)建activity事件回調(diào)函數(shù)(Creating event callbacks to the activity)
In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.
For example, if a news application has two fragments in an activity—one to show a list of articles (fragment A) and another to display an article (fragment B)—then fragment A must tell the activity when a list item is selected so that it can tell fragment B to display the article. In this case, the OnArticleSelectedListener interface is declared inside fragment A:
在一些情況下,你可能需要fragment與activity共享事件。這樣做的一個好方法是在fragment內(nèi)部定義一個回調(diào)接口,并需要宿主activity實現(xiàn)它。當(dāng)activity通過接口接收到回調(diào)時,可以在必要時與布局中的其它fragment共享信息。
舉個例子,如果新聞應(yīng)用的actvity中有兩個fragment——一個顯示文章列表(fragment A),另一個顯示一篇文章(fragment B)——然后fragment A 必須要告訴activity列表項何時被選種,這樣,activity可以通知fragment B顯示這篇文章。這種情況下,在fragment A內(nèi)部聲明接口OnArticleSelectedListener:
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
Then the activity that hosts the fragment implements the OnArticleSelectedListener interface and overrides onArticleSelected() to notify fragment B of the event from fragment A. To ensure that the host activity implements this interface, fragment A's onAttach() callback method (which the system calls when adding the fragment to the activity) instantiates an instance of OnArticleSelectedListener by casting the Activity that is passed into onAttach():
然后fragment的宿主activity實現(xiàn)了OnArticleSelectedListener接口,并且重寫onArticleSelected()以通知fragment B來自于fragment A的事件。為了確保宿主activity實現(xiàn)了這個接口,fragment A的onAttach()回調(diào)函數(shù)(當(dāng)添加fragment到activity中時系統(tǒng)會調(diào)用它)通過作為參數(shù)傳入onAttach()的activity的類型轉(zhuǎn)換來實例化一個OnArticleSelectedListener實例。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
...
}
If the activity has not implemented the interface, then the fragment throws a ClassCastException. On success, the mListener member holds a reference to activity's implementation of OnArticleSelectedListener, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener interface. For example, if fragment A is an extension of ListFragment, each time the user clicks a list item, the system calls onListItemClick() in the fragment, which then calls onArticleSelected() to share the event with the activity:
如果activity沒有實現(xiàn)這個接口,那么fragment會拋出一個ClassCaseException異常。一旦成功,mListener成員會保留一個activity的OnArticleSelectedListener實現(xiàn)的引用,由此fragment A可以通過調(diào)用由OnArticleSelectedListener接口定義的方法與activity共享事件。例如,如果fragment A是ListFragment的子類,每次用戶點擊列表項時,系統(tǒng)都會調(diào)用fragment的onListItemClick()事件,然后fragment調(diào)用onArticleSelected()來與activity共享事件。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
...
}
The id parameter passed to onListItemClick() is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application's ContentProvider.
More information about using a content provider is available in the Content Providers document.
傳遞給onListItemClick()的參數(shù)id是點擊的列表項行id,activity(或者其它fragment)用以從應(yīng)用的ContentProvider獲取文章。
關(guān)于使用content provider的更多資料可以在在Content Providers文檔獲取。
添加項目到Action Bar(Adding items to the Action Bar)
Your fragments can contribute menu items to the activity's Options Menu (and, consequently, the Action Bar) by implementing onCreateOptionsMenu(). In order for this method to receive calls, however, you must call setHasOptionsMenu() during onCreate(), to indicate that the fragment would like to add items to the Options Menu (otherwise, the fragment will not receive a call to onCreateOptionsMenu()).
你的fragments可以通過實現(xiàn)onCreateOptionsMenu()來構(gòu)建菜單項到activity的Options Menu(因此Action Bar也一樣)。為了使用這個方法接收到調(diào)用,不管怎樣,你必須在onCreate()期間調(diào)用setHasOptionsMenu(),來指明想要添加項目到Options Menu的那個fragment(否則,fragment將接收不到onCreateOptionsMenu()的調(diào)用)。
Any items that you then add to the Options Menu from the fragment are appended to the existing menu items. The fragment also receives callbacks to onOptionsItemSelected() when a menu item is selected.
任何想要在fragment中的Options Menu添加的項目都追加到已有的菜單項后面。當(dāng)菜單項被選中時,fragment也會接收到對onOptionsItemSelected()的回調(diào)。
You can also register a view in your fragment layout to provide a context menu by calling registerForContextMenu(). When the user opens the context menu, the fragment receives a call to onCreateContextMenu(). When the user selects an item, the fragment receives a call to onContextItemSelected().
你也可以通過調(diào)用registerForContextMenu()在fragment布局中注冊一個view以提供一個context menu。當(dāng)用戶打開context menu時,fragment接收到對onCreateContextMenu()的回調(diào)。當(dāng)用戶選中一個項目時,fragment接收到對onContextItemSelected()的回調(diào)。
Note: Although your fragment receives an on-item-selected callback for each menu item it adds, the activity is first to receive the respective callback when the user selects a menu item. If the activity's implementation of the on-item-selected callback does not handle the selected item, then the event is passed to the fragment's callback. This is true for the Options Menu and context menus.
注意:盡管你的fragment會接收到為添加到每個菜單項被選擇菜單項的回調(diào),但當(dāng)用戶選擇一個菜單項時,activity會首先接收到對應(yīng)的回調(diào)。如果activity的選擇菜單項回調(diào)的實現(xiàn)沒有處理被選中的項目,那么該事件被傳遞給fragment的回調(diào)。這同樣適用于Options Menu和context menu。
For more information about menus, see Creating Menus and Using the Action Bar.
關(guān)于menu的更多信息,參考Creating Menus 和Using the Action Bar。
操縱fragment生命周期(Handling the Fragment Lifecycle)
Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like an activity, a fragment can exist in three states:
Resumed
The fragment is visible in the running activity.
Paused
Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn't cover the entire screen).
Stopped
The fragment is not visible. Either the host activity has been stopped or the fragment has been removed from the activity but added to the back stack. A stopped fragment is still alive (all state and member information is retained by the system). However, it is no longer visible to the user and will be killed if the activity is killed.
管理fragment生命周期與管理activity生命周期很相像。像activity一樣,fragment也有三種狀態(tài):
Resumed:
fragment在運行中的activity可見。
Paused
另一個activity處于前臺且得到焦點,但是這個fragment所在的activity仍然可見(前臺activity部分透明,或者沒有覆蓋全屏)。
Stopped
fragment不可見。要么宿主activity已經(jīng)停止,要么fragment已經(jīng)從activity上移除,但已被添加到后臺棧中。一個停止的fragment仍然活著(所有狀態(tài)和成員信息仍然由系統(tǒng)保留著)。但是,它對用戶來講已經(jīng)不再可見,并且如果activity被殺掉,它也將被殺掉。
Also like an activity, you can retain the state of a fragment using a Bundle, in case the activity's process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment's onSaveInstanceState() callback and restore it during either onCreate(), onCreateView(), or onActivityCreated(). For more information about saving state, see the Activities document.
同activity類似的還有,你也可以用Bundle保存fragment狀態(tài),萬一activity的進程被殺掉了,并且在activity被重新創(chuàng)建時,你需要恢復(fù)fragment狀態(tài)。在回調(diào)執(zhí)行fragment的onSaveInstanceState()期間可以保存狀態(tài),在onCreate(),onCreateView(),或者onActvityCreate()中可以恢復(fù)狀態(tài)。更多關(guān)于保存狀態(tài)的信息,參考Activities文檔。
The most significant difference in lifecycle between an activity and a fragment is how one is stored in its respective back stack. An activity is placed into a back stack of activities that's managed by the system when it's stopped, by default (so that the user can navigate back to it with the BACK key, as discussed in Tasks and Back Stack). However, a fragment is placed into a back stack managed by the host activity only when you explicitly request that the instance be saved by calling addToBackStack() during a transaction that removes the fragment.
在生命周期方面,activity與fragment之間一個很重要的不同,就是在各自的后臺棧中是如何存儲的。當(dāng)activity停止時,默認(rèn)情況下,activity被安置在由系統(tǒng)管理的activity后臺棧中(因此用戶可以按BACK鍵回退導(dǎo)航,就像在Tasks和后臺棧中討論的那樣)。但是,僅當(dāng)你在一個事務(wù)被移除時,通過顯式調(diào)用addToBackStack()請求保存的實例,該fragment才被置于由宿主activity管理的后臺棧。
Otherwise, managing the fragment lifecycle is very similar to managing the activity lifecycle. So, the same practices for managing the activity lifecycle also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.
除此之外,管理fragment的生命周期與管理activity的生命周期非常相似。所以,管理activity生命周期的實踐同樣也適用于fragment。你需要了解的,僅僅是activity的生命周期如何影響fragment的的。
與activity生命周期的協(xié)調(diào)合作(Coordinating with the activity lifecycle)
The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause(), each fragment in the activity receives onPause().
fragment所生存的activity生命周期直接影響著fragment的生命周期,由此針對activity的每一個生命周期回調(diào)都會引發(fā)一個fragment類似的回調(diào)。例如,當(dāng)activity接收到onPause()時,這個activity之中的每個fragment都會接收到onPause()。
Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment's UI. These additional callback methods are:
onAttach()
Called when the fragment has been associated with the activity (the Activity is passed in here).
onCreateView()
Called to create the view hierarchy associated with the fragment.
onActivityCreated()
Called when the activity's onCreate() method has returned.
onDestroyView()
Called when the view hierarchy associated with the fragment is being removed.
onDetach()
Called when the fragment is being disassociated from the activity.
Fragment有一些額外的生命周期回調(diào)方法,然而,為了處理像是創(chuàng)建和銷毀fragment界面,它與activity進行獨特的交互。這些額外的回調(diào)方法是:
onAttach()
當(dāng)fragment被綁定到activity時調(diào)用(Activity會被傳入)。
onCreateView()
創(chuàng)建與fragment相關(guān)的視圖體系時被調(diào)用。
onActivityCreated()
當(dāng)activity的onCreate()函數(shù)返回時被調(diào)用。
onDestroyView()
當(dāng)與fragment關(guān)聯(lián)的視圖體系正被移除時被調(diào)用。
onDetach()
當(dāng)fragment正與activity解除關(guān)聯(lián)時被調(diào)用。
The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated by figure 3. In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. For example, when the activity has received its onCreate() callback, a fragment in the activity receives no more than the onActivityCreated() callback.
fragment的生命周期流程實際上是受其宿主activity影響,如圖3所示。在這張圖中,可以看到activity的每個連續(xù)狀態(tài)是如何決定fragment可能接收到哪個回調(diào)函數(shù)的。例如,當(dāng)activity接收到它的onCreate()回調(diào)時,activity之中的fragment接收到的僅僅是onActivityCreated()回調(diào)。
Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.
一旦activity處于resumed狀態(tài),則可以在activity中自由的添加或者移除fragment。因此,只有當(dāng)activity處于resumed狀態(tài)時,fragment的生命周期才可以獨立變化。
However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.
然而,當(dāng)activity離開恢復(fù)狀態(tài)時,fragment再一次被activity推入它的生命周期中。
范例(Example)
To bring everything discussed in this document together, here's an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.
Note: The complete source code for this activity is available in FragmentLayout.java.
The main activity applies a layout in the usual way, during onCreate():
為了把這篇文檔里的內(nèi)容放到一起討論,這里有一個使用兩個fragment創(chuàng)建雙區(qū)域布局的activity的范例。這個activity下面包含的一個fragment用來顯示莎士比亞戲劇列表,另一個fragment則用來在列表項被選中時顯示該戲劇的概要。它也表明了如何基于不同屏幕配置提供不同的fragment配置。
注意:這個activity的全部源代碼可以在FragmentLayout.java獲取。
一個問題
在android3.0以下版本 不支持Fragment使用 需要導(dǎo)入D:\Android\android-sdk-windows\extras\android\support\v4\android_suport_v4.jar包
并且 主Activity要繼承FragmentActivity方可繼續(xù)使用
在onCreate()期間,主activity用常用的方法應(yīng)用了一個布局。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
}
The layout applied is fragment_layout.xml:
被應(yīng)用的布局是fragment_layout.xml
<LinearLayout xmlns:android="http://schemas./apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"/>
<FrameLayout android:id="@+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground"/>
</LinearLayout>
Using this layout, the system instantiates the TitlesFragment (which lists the play titles) as soon as the activity loads the layout, while the FrameLayout (where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you'll see below, it's not until the user selects an item from the list that a fragment is placed into the FrameLayout.
However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml.
使用這個布局,activity一載入布局,系統(tǒng)就實例化TitlesFragment(它列出了戲劇標(biāo)題),盡管在屏幕右方的FrameLayout(其中的fragment用來顯示即將列出的戲劇概要)消耗了內(nèi)存,但是起先是空的。就像你下面將要看到的,直到用戶從列表中選擇一項時,fragment才被置于FrameLayout中。
然而,并不是所有的屏幕配置都足夠?qū)?,以顯示并排的戲劇列表和摘要。所以,上面的布局僅適用于橫向屏幕配置,且配置保存在res/layout-land/fragment_layout.xml。
Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved atres/layout/fragment_layout.xml:
因此,當(dāng)屏幕被置于縱向時,系統(tǒng)會適應(yīng)下面的布局,它被保存在res/layout/fragment_layout.xml:
<FrameLayout xmlns:android="http://schemas./apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles"
android:layout_width="match_parent" android:layout_height="match_parent"/>
</FrameLayout>
This layout includes only TitlesFragment. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.
Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment, which shows the list of Shakespeare play titles. This fragment extends ListFragment and relies on it to handle most of the list view work.
As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to theFrameLayout), or start a new activity (where the fragment can be shown).
這個布局只包含了TitlesFragment。這就意味著,當(dāng)設(shè)備置于縱向時,只有戲劇標(biāo)題列表是可見的。因此,當(dāng)用戶點擊這個配置中的一個列表項時,應(yīng)用程序?qū)㈤_啟一個新的activity來顯示摘要,而不是載入第二個fragment。
接下來,你可以看到這在fragment類里是如何完成的。首先是顯示莎士比亞戲劇標(biāo)題的TitlesFragment。這個fragment繼承于ListFragment,并且靠它處理大部分的列表視圖工作。
就像你看到的這段代碼,注意當(dāng)用戶點擊一個列表項時會產(chǎn)生兩個可能的行為:這依賴于兩個布局哪個處于激活狀態(tài),它要么創(chuàng)建并顯示一個新的fragment以在同一個activity中顯示概要內(nèi)容(添加fragment到FrameLayout),要么啟動一個新的activity(在fragment可顯示的地方)。
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
The second fragment, DetailsFragment shows the play summary for the item selected from the list from TitlesFragment:
第二個fragment,DetailsFragment在TitlesFragment的列表項被選中時顯示戲劇概要。
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
}
Recall from the TitlesFragment class, that, if the user clicks a list item and the current layout does not include the R.id.details view (which is where the DetailsFragment belongs), then the application starts the DetailsActivity activity to display the content of the item.
Here is the DetailsActivity, which simply embeds theDetailsFragment to display the selected play summary when the screen is in portrait orientation:
從TitlesFragment類回想一下,如果用戶點擊列表項,并且目前的區(qū)域不包含R.id.details視圖(這是DetailsFragment的所在),那么應(yīng)用程序啟動DetailsActivity以顯示列表項內(nèi)容。
下面是DetailsActivity,它只是在屏幕縱向時,嵌入DetailFragment以顯示被選中的戲劇概要。
public static class DetailsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment alongside the TitlesFragment. This can happen if the user begins the DetailsActivity while in portrait orientation, but then rotates to landscape (which restarts the current activity).
For more samples using fragments (and complete source files for this example), see the sample code available in ApiDemos (available for download from the Samples SDK component).
請注意,如果配置是橫向的,這個activity會結(jié)束掉自己,使主acitivity可以接管并在TitlesFragment旁顯示DetailsFragment。這種情況可能會發(fā)生在,用戶在縱向時開啟了DetailsActivity,但是之后旋轉(zhuǎn)到橫向(它重新啟動了當(dāng)前activity)。
更多的關(guān)于使用fragment的例子(還有這個例子的完整源碼),請參閱ApiDemos中的示例代碼(從 Samples SDK component中下載可用的)。