《Android》『Fragment』- 於程式碼中動態操作 Fragment (動態載入)
《Android Developers 參考文獻》
《簡單介紹》
在上一篇Fragment 的基本用法(靜態載入)中,我們已經知道該如何直接在介面佈局中加入 Fragment,接下來這一篇要來談談如何於程式碼中加入 Fragment,也就是動態載入,透過動態載入的方式,我們可以更加靈活的控管所需的頁面呈現方式,而不會受限於已設定好的 Fragment 中。
《FragmentManager 的使用方式》
要實作動態載入 Fragment,首先要知道如何使用 FragmentManager,程式碼片段如下 –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private Fragment01 mFragment01; FragmentManager mFragmentManager; mFragmentManager = getFragmentManager(); mFragmentManager.beginTransaction() .setCustomAnimations(R.animator.rotate_alpha_in, R.animator.rotate_alpha_out, R.animator.rotate_alpha_in, R.animator.rotate_alpha_out) .add(R.id.frameLayout, Fragment01, "TAG") .replace(R.id.frameLayout, Fragment01, "TAG") .addToBackStack(null) .commit(); |
Fragment 動態載入範例
要實作動態載入,首先必須宣告一個 FragmentManager 物件,接著再透過此物件所提供的方法,進一步進行 Fragment 的控管,一些常用的方法條列如下 –
.beginTransaction()
要求 FragmentManager 回傳一個 FragmentTransaction 物件,用以進行 Fragment 的切換。
.setCustomAnimations()
設定切換 Fragment 時所使用的動畫效果。
.add()
將所選擇的 Fragment 加入指定的程式操作介面。
.remove()
將所選擇的 Fragment 從程式操作介面中移除。
.replace()
將指定的 Fragment取代目前程式畫面中的 Fragment。等同於先呼叫 .remove() 再呼叫 .add()。
.detach()
將指定的 Fragment 畫面刪除。
.attach()
將之前 detach 的 Fragment 畫面重新建立。
.hide()
將指定的 Fragment 畫面隱藏。
.show()
將之前 hide 的 Fragment 畫面重新建立。
.addToBackStack()
將此次 Fragment 的切換加入系統的 Back Stack,當按下回上頁按鈕時,就會回復到此次切換前的狀態。
.commit()
要求系統開始執行 Fragment 的切換,寫在所有方法的最後。
《Fragment 的動態載入方法》
知道 FragmentManager 的宣告與使用方式後,我們就可以開始實作 Fragment 的動態載入,以下透過程式碼片段,列出動態載入的方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package tw.android; import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; public class MainActivity extends Activity { private Fragment01 mFragment01; private Fragment02 mFragment02; private FragmentManager mFragmentMgr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFragment01 = new Fragment01(); mFragment02 = new Fragment02(); mFragmentMgr = getFragmentManager(); mFragmentMgr.beginTransaction() .replace(R.id.frameLay, mFragment01, "TAG-mFragment01") .commit(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } public void showResult(String sName, String sTel, String sAddress) { mFragment02.setResult(sName, sTel, sAddress); mFragmentMgr.beginTransaction() .setCustomAnimations(R.animator.rotate_alpha_in, R.animator.rotate_alpha_out, R.animator.rotate_alpha_in, R.animator.rotate_alpha_out) .replace(R.id.frameLay, mFragment02, "TAG-mFragment02") .addToBackStack(null) .commit(); //mFragmentMgr.executePendingTransactions(); } public void BackToFragment01() { mFragmentMgr.popBackStack(); } } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity" > <FrameLayout android:id="@+id/frameLay" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> |
activity_main.xml
首先在 MainActivity 中,宣告了兩個 Fragment 物件,分別是 mFragment01 與 mFragment02,並宣告了一個名為 mFragmentMgr 的FragmentManager 物件 ,用以控管兩個不同 Fragment 之間的切換。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package tw.android; import android.app.AlertDialog; import android.app.Fragment; import android.content.DialogInterface; import android.os.Bundle; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; public class Fragment01 extends Fragment { private EditText mEdtName, mEdtTel, mEdtAddr; private Button mBtnInput; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment01, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mEdtName = (EditText) getView().findViewById(R.id.edtName); mEdtTel = (EditText) getView().findViewById(R.id.edtTel); mEdtAddr = (EditText) getView().findViewById(R.id.edtAddr); mBtnInput = (Button) getView().findViewById(R.id.btnInput); mEdtAddr.setHorizontallyScrolling(true); mEdtAddr.setOnKeyListener(edtAddrOnKey); mBtnInput.setOnClickListener(btnInputOnClick); } private View.OnClickListener btnInputOnClick = new View.OnClickListener() { @Override public void onClick(View v) { ((MainActivity)getActivity()).showResult(mEdtName.getText().toString(), mEdtTel.getText().toString(), mEdtAddr.getText().toString()); } }; private View.OnKeyListener edtAddrOnKey = new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { //... } return false; } }; } |
Fragment01.java
這邊要特別注意的是在 onKeyListener() 中所返回的布林值是用來指示你是否已經完成了這個事件、應不應該再進一步處理它。也就是說,返回 true 表示你已經處理了這個事件而且到此為止;返回 false 則表示你還沒有處理它,或者是這個事件應該繼續交給其他 onKey 的偵聽器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package tw.android; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; public class Fragment02 extends Fragment { private TextView mTxtR; private Button mBtnBackToFragment01; private String mStrName, mStrTel, mStrAddress; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment02, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mTxtR = (TextView) getView().findViewById(R.id.txtR); mTxtR.setText(mStrName + "\n" + mStrTel + "\n" + mStrAddress); mBtnBackToFragment01 = (Button) getView().findViewById(R.id.btnBackToFragment01); mBtnBackToFragment01.setOnClickListener(btnBackToFragment01); } private View.OnClickListener btnBackToFragment01 = new View.OnClickListener() { @Override public void onClick(View v) { ((MainActivity) getActivity()).BackToFragment01(); } }; public void setResult(String sName, String sTel, String sAddress) { mStrName = sName; mStrTel = sTel; mStrAddress = sAddress; } } |
Fragment02.java
從這兩個 Fragment 中我們可以發現,於 MainActivity 中宣告的 public 方法,我們可以在每個 Fragment 中直接呼叫來使用, 像是((MainActivity) getActivity()).BackToFragment01() 以及 ((MainActivity)getActivity()).showResult(),下一篇將來討論如何透過 Interface 於 MainActivity 中控管數個不同的 Fragment。
臉書留言
一般留言