Fragment
Fragment中文解釋可以理解為“碎片”,Activity的碎片
一個Activity可以有多個Fragment,一個Frgament可以在多個Activity中
Fragment可以看作是一個Activity。
Fragment也可以看作為Activity的一個控件。
為什么Fragment可以看作是一個Activity?
Fragment的生命周期與Activity類似
Fragment的生命周
二,與Activity生命周期的對比
就是多了onAttach()與Activity關聯時調用,只調用一次 onDetach()與Activity失去關聯時調用,只調用一次
onCreateView() 插入Activity時調用,只調用一次 onDestoryView()移除Activity時調用,只調用一次
onActivityCreatde()Activity的onCreate()方法發生時調用
為什么說Fragment相對與一個控件呢?
其實Fragment的一個重要作用就是把布局文件變成一個View對象,然后把View對象插入到Activity中
怎么把布局變成View對象呢?
1 public class MyFragment extends Fragment{ 2 @Override 3 public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { 4 View view = inflater.inflate(R.layout.fragment, container, false); 5 return view; 6 } 7 }
這樣就可以實現把R.layout.fragment布局文件變成view對象並在創建MyFragment對象時返回,相當與把這個布局變成了一個自定義的控件
然后就可以在我們的另外一個布局文件中直接用我們的View對象。把這個布局插入到Activity類中。
在xml文件中加入這個控件就可以了,注意一定要定義id,和name,name屬性為Fragement類的具體位置(包名.類名)
1 <fragment 2 android:id="@+id/fragment" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:name="com.example.z_fragment.MyFragment"/>
這個效果就和我們之前講過的自定義控件的一個方法一樣。代碼如下
1 <include layout="@layout/fragment" 2 android:layout_width="wrap_content" 3 android:layout_height="wrap_content"/>
效果是一模一樣的。
這種方法叫靜態加載。
所以當然我們也可以和之前自定義控件一樣,再Activity中實現自定義控件里面的小控件的響應事件,用<fragment>還能再Fragment中設置。
<include>方法是在Activity文件種直接findViewById這些控件,fragment也可以這樣在Activity種findViewById。
還可以在fragment類種定義,不過findViewById方法要在View對象中實現,例如:
1 public class MyFragment extends Fragment{ 2 private Button bt; 3 public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { 4 View view = inflater.inflate(R.layout.fragment, container, false); 5 bt = (Button)view.findViewById(R.id.btf); 6 bt.setOnClickListener(new OnClickListener() { 7 public void onClick(View v) { 8 } 9 }); 10 return view; 11 } 12 }
不過值得注意的是,如果fragment中定義了響應的具體事件,Activity中也定義了,這樣的話會只執行Activity中的響應。
說完了靜態加載,當然也有動態加載拉。
動態加載則需要使用FragmentManger類中的事務 通過事務的add(),remove(),replace()等方法,添加,刪除,替換Fragment對象。
1 MyFragment fragment = new MyFragment(); 2 //加載frgament 3 FragmentManager fragmentManger = getFragmentManager();//Fragment管理器 4 FragmentTransaction beginTransaction = fragmentManger.beginTransaction();//Fragment事務 5 beginTransaction.add(R.id.line, fragment);//添加Fragment 6 beginTransaction.addToBackStack(null);//把命令加載到棧 7 beginTransaction.commit();//加載棧中的事務
上面的代碼是把fragment對象加載到Activity布局文件中的中的一個編號為(R.id.line)的線性布局當中。
這樣我們就可以在應用進行的時候隨時插入或者移出frgament,或者控件
說起隨時插入或者移出控件還有一種方法(ViewStub標簽)
1 <ViewStub 2 android:id="@+id/vs" 3 android:layout ="@layout/fragment"" 4 android:layout_width="wrap_content" 5 android:layout_height="wrap_content"/>
然后通過實例化這個控件,通過它的inflate()惰性加載的方法把里面的東西顯示出來
其實控件自身也有隱藏的屬性,android:visibility=“gone”就是隱藏,然后調用方法變成“visbe”就不隱藏。
說到這里,順便說一些布局注意事項把,我們用布局的時候盡量多用線性布局和相對布局 LinearLayout和RelativeLayout。
nergae標簽可以把控件組合起來:
例如:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <ProgressBar 7 android:id="@+id/progressBar1" 8 style="?android:attr/progressBarStyleLarge" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" /> 11 <TextView 12 android:id="@+id/textView1" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="TextView" /> 16 </LinearLayout>

1 <?xml version="1.0" encoding="utf-8"?> 2 <merge xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <ProgressBar 7 android:id="@+id/progressBar1" 8 style="?android:attr/progressBarStyleLarge" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" /> 11 <TextView 12 android:id="@+id/textView1" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="TextView" /> 16 </merge>

相當與一個禎布局。
好,讓我們回到Fragment的最后一個知識點,Fragment與Activity通信。
(1)Fragment可調用getActivity()方法獲取它所在的Activity
(2)Activity可調用FragmentManager的findFrgamentById()或findFragmentByTah()方法獲取Fragment
(3)Activity ->Frgament:在Activity中創建Bundle數據包,並調用Fragment的setArgument(Bundle bundle)方法
(4)Fragment ->Activity:需要在Fragment中定義一個內部會調接口,再讓包含該Fragment的Activity實現該回調接口。這樣Fragment可以用該回調方法將數據傳遞給Activity。
實現3:
在Activity中:
1 MyFragment fragment = new MyFragment(); 2 String text = et.getText().toString(); 3 Bundle bundle = new Bundle(); 4 bundle.putString("text", text);//"text"是bundle內部的信息的標識名 5 fragment.setArguments(bundle);
在Fragment中:
1 //Fragment.getArguments方法獲取傳遞過來的bundle對象的信息標識名為“text”的數據 2 String text = getArguments().getString("text");//"text"是bundle內部的信息的標識名
實現4:
在Fragment中:
(定義內部接口)
1 private String s="收到了"; 2 private MyListener listener; 3 public interface MyListener{ 4 public void get(String s); 5 } 6 public void onAttach(Activity activity){ 7 listener =(MyListener)activity;//把Activity強制變成自定義接口 8 super.onAttach(activity); 9 }
然后在onCreateView中調用自定義接口的get方法:listener.get(s);
在Activity中:
連接自定義接口,實現get方法:
1 @Override 2 public void get(String s) { 3 tv.setText(s); 4 }
下面我用一個案例來總結上面所學的知識:
這個app定義了兩個Activity和兩個Fragment
第一個MianActivity包含兩個按鈕一個是靜態加載,一個是動態加載,有一個EditText和TextView用來與MyFragment通信,還有一個Linerlayout用來放動態加載的Fragment
第二個MainActivtiy2靜態加載了MyFragemnt,Myfragemnt有一個按鈕,在MianActivity2實現了響應事件
第一個MyFragment關鍵是有一個按鈕,用來實現動態加載響應后切換到MyFragment2,還有一個TextView用來與MainActivity通信
第二個MyFragment2關鍵是有一個按鈕,用ViewStud墮態加載fragment。
示例代碼:
MianActivity:
public class MainActivity extends Activity implements MyListener{ private Button bt1,bt2; private EditText et; private TextView tv; private int n=0; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt1 = (Button)findViewById(R.id.button1); bt2 = (Button)findViewById(R.id.button2); et = (EditText)findViewById(R.id.et); tv = (TextView)findViewById(R.id.tv); //靜態加載按鈕 bt1.setOnClickListener(new OnClickListener() { public void onClick(View v) { Intent intent = new Intent(MainActivity.this,MainActivity2.class); startActivity(intent); } }); //動態加載按鈕 bt2.setOnClickListener(new OnClickListener() { public void onClick(View v) { n++; MyFragment fragment = new MyFragment(); //向fragment中發送信息 String text = et.getText().toString(); Bundle bundle = new Bundle(); bundle.putString("text", text);//"text"是bundle內部的信息的標識名 ////Fragment.setArguments方法發送bundle對象給Activity fragment.setArguments(bundle); //加載frgament FragmentManager fragmentManger = getFragmentManager();//Fragment管理器 FragmentTransaction beginTransaction = fragmentManger.beginTransaction();//Fragment事務 if(n==1) beginTransaction.add(R.id.line, fragment);//添加Fragment else beginTransaction.replace(R.id.line, fragment);//替換Fragment beginTransaction.addToBackStack(null);//把命令加載到棧 beginTransaction.commit();//加載棧中的事務 } }); } @Override public void get(String s) { tv.setText(s); } }
MainAtivity2:
public class MainActivity2 extends Activity { private Button bt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); bt = (Button)findViewById(R.id.btf); bt.setOnClickListener(new OnClickListener() { public void onClick(View v) { Toast toast = Toast.makeText(MainActivity2.this, "被點了", Toast.LENGTH_SHORT); toast.show(); } }); } }
MyFragment:
public class MyFragment extends Fragment{ private Button bt; private TextView tv; private String s="收到了"; private MyListener listener; public interface MyListener{ public void get(String s); } public void onAttach(Activity activity){ listener =(MyListener)activity;//把Activity強制變成自定義接口 super.onAttach(activity); } public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment, container, false); bt = (Button)view.findViewById(R.id.btf); tv = (TextView)view.findViewById(R.id.tvf1); //Fragment.getArguments方法獲取傳遞過來的bundle對象的信息標識名為“text”的數據 String text = getArguments().getString("text");//"text"是bundle內部的信息的標識名 tv.setText(text); listener.get(s); //點擊按鈕切換另外一個MyFragment2 bt.setOnClickListener(new OnClickListener() { public void onClick(View v) { MyFragment2 fragment = new MyFragment2(); FragmentManager fragmentManger = getFragmentManager(); FragmentTransaction beginTransaction = fragmentManger.beginTransaction(); beginTransaction.replace(R.id.line, fragment); beginTransaction.addToBackStack(null); beginTransaction.commit(); } }); return view; } }
MyFragment2:
public class MyFragment2 extends Fragment{ private Button bt; private ViewStub vs; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View view = inflater.inflate(R.layout.fragment2, container, false); bt = (Button)view.findViewById(R.id.btf2); vs = (ViewStub)view.findViewById(R.id.vs); bt.setOnClickListener(new OnClickListener() { public void onClick(View v) { vs.inflate(); } }); return view; } }
MainAtivity界面:
MianAtivity2和MyFragment2的界面:(其中MyFragmnet2隱藏了一個MyFragemnt界面)
MyFragmet2的界面
運行結果:
因為這只是示例的例子,所以沒用優化,第五張圖的上面的改變按鈕是按不了的,因為隱藏的控件已經出來了,再按程序會崩潰
第二個按鈕是沒有響應事件的,因為它是直接調用布局,沒用再MainActivitiy中設置隱藏控件的子控件的響應。
雖然再MyFragment中有設置,但是它沒用調用MyFragment,而是直接調用布局。
include也是同樣道理,但是fragment卻不同,因為它是布局調用MyFragment對象。
如果有什么錯誤,或者我理解錯誤或不當的,懇請大家糾正,謝謝!嘻嘻嘻