Building a Dynamic UI with Fragments
1. create a fragment
可以把fragment看作爲activity的一個模塊化的部分,它擁有自己的生命週期,接受自己的輸入,並且在activity運行中可以添加或者刪除。(sort of like a “sub activity” that you can reuse in different activities). This lesson shows how to extend the Fragment class using the Support Library so your app remains compatible with devices running system versions as low as Android 1.6.
1.1 create a fragment class
創建一個fragment,繼承Fragment類,然後重寫重要的生命週期來添加我們的代碼邏輯(和activity類似)。不同的是Fragment必須使用oncreateView()回調來定義佈局。
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.ViewGroup;
public class ArticleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.article_view, container, false);
}
}
1.2 add a fragment to an activity using xml
each instance of a Fragment class must be associated with a parent FragmentActivity.
Note: FragmentActivity is a special activity provided in the Support Library to handle fragments on system versions older than API level 11. If the lowest system version you support is API level 11 or higher, then you can use a regular Activity.
fragment的xml佈局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="@+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.android.fragments.ArticleFragment"
android:id="@+id/article_fragment"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
2. building a flexible UI
Fragment類提供了方法允許我們在運行的時候動態的添加,移除和替代fragment。
2.1 add a fragment to an activity at runtime
爲了執行添加和刪除的事務,我們必須使用FragmentManager來創建一個FragmentTransaction。另外,我們需要添加初始的fragment到activity中。爲了添加一個fragment我們的layout中必須包含一個view容器方便插入。在這裏我們使用FrameLayout來表示fragment container。
res/layout/news_articles.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Inside your activity, call getSupportFragmentManager()
to get a FragmentManager
using the Support Library APIs. Then call beginTransaction()
to create a FragmentTransaction
and call add()
to add a fragment.
You can perform multiple fragment transaction for the activity using the same FragmentTransaction.
When you’re ready to make the changes, you must call commit()
.
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
}
2.2 replace one fragment with another
如果需要撤銷類的功能的話,就需要再must call addToBackStack()
before you commit the FragmentTransaction
。如果這麼做了,那麼移除的fragment就會再stopped狀態,否則直接進行銷燬。
Example of replacing one fragment with another:
// Create fragment and give it an argument specifying the article it should show
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
3. communicating with other fragment
All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly。
所有的frag和fragment之間的通信應該通過activity來實現的,兩個fragment之間不應該直接通信。
3.1 define an interface
爲了使fragment和它的activity進行通信,在Fragment類中定義一個接口,並且在activity中繼承他。Fragment在它的onattach()生命週期中獲取這個接口並且調用接口中的方法。
Here is an example of Fragment to Activity communication:
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
Now the fragment can deliver messages to the activity by calling the onArticleSelected()
method (or other methods in the interface) using the mCallback
instance of the OnHeadlineSelectedListener
interface.
3.2 implement the interface
In order to receive event callbacks from the fragment, the activity that hosts it must implement the interface defined in the fragment class.
爲了得到事件的回調,activity必須implement fragment中的接口
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
}
}
3.3 deliver a message to a fragment
activity可以直接通過findFragmentById()
得到Fragment的實例,然後直接調用fragment的公共方法。
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
至此,結束