願你的快樂與歲月無關,願你的純真與經歷無關。
滄海桑田後依舊乘風破浪,塵埃落定後依舊熾熱歡暢!!!
整理一下自己的Fragment知識:
當今手機已然成爲了日用品,就連平板電腦也成爲辦公所需,那麼相應的程序開發在必要的界面就應該實現手機和平板要進行兼顧的情景,甚至在手機進行橫豎屏幕的切換時候也要達到適配的效果,看看下面這兩張圖片:
手機豎屏:
手機橫屏:
上面的兩張圖片是我手機上文件管理的使用情況,當手機是豎屏的時候就只顯示第一張圖片,當手機切換至橫屏的時候就會顯示爲第二個界面,我們也可以達到這種效果,就要使用到Fragment的知識,我們看看吧!
碎片Fragment
是一種可以嵌入在活動當中的UI片段,可以是程序更合理的利用屏幕空間。Fragmeng也有自己的UI界面,也有自己的生命週期。和Activity有些像。
Fragment的聲明週期
圖片來源:百度搜索
對於Activity的生命週期就不多說,Fragment的聲明週期多出5種方法,說明一下:
onAttach():當碎片與活動建立聯繫的時候調用。
onCreateView():爲碎片創建視圖時調用。
onActivityCreated():確保與碎片相關聯的活動一定已經創建完畢的時候調用。
···
onDestoryView():當與碎片關聯的視圖被移除的時候調用。
onDetach():當碎片與活動解除關聯的時候調用。
使用Fragmeng
那麼我們看看怎麼使用Fragment:
在Activity中使用Fragment有兩種方法:
1:使用靜態調用
step1: 創建一個FirstFragment類並繼承Fragment,如下:
public class FirstFragment extends Fragment {
private static final String TAG = "FirstFragment";
public FirstFragment() {
// Required empty public constructor
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i(TAG, "onAttach: ");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: ");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i(TAG, "onCreateView: ");
return inflater.inflate(R.layout.fragment_first, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG, "onActivityCreated: ");
}
@Override
public void onStart() {
super.onStart();
Log.i(TAG, "onStart: ");
}
@Override
public void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
}
@Override
public void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
}
@Override
public void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.i(TAG, "onDestroyView: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
@Override
public void onDetach() {
super.onDetach();
Log.i(TAG, "onDetach: ");
}
}
對於Fragment加載的佈局:fragment_first.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="wedfrend.wang.privateproject.fragment.FirstFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
上述方法中只有在onCreatView()
添加了加載佈局代碼:
inflater.inflate(R.layout.fragment_first, container, false);
並將View返回。
step2:創建一個FragmentActivity繼承AppCompatActivity:
這裏多說一句:在之前的android開發中,我們創建Activity繼承的是Activity,創建含有FragmentActivity繼承的是FragmentActivity,但是在V7包中,我們只需要繼承AppCompatActivity就可以了:
public class FragmentActivity extends AppCompatActivity{
private static final String TAG = "FragmentActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: ");
setContentView(R.layout.activity_recycle_view);
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart: ");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart: ");
}
}
對應佈局activity_recycle_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="wedfrend.wang.privateproject.recycle.RecycleViewActivity">
<fragment
android:id="@+id/news_title_fragment"
app:layout_widthPercent="100%"
app:layout_heightPercent="100%"
android:layout_alignParentRight="true"
android:name="wedfrend.wang.privateproject.fragment.FirstFragment"
tools:layout="@layout/fragment_right">
</fragment>
</android.support.percent.PercentRelativeLayout>
這裏使用百分比佈局。我們說創建的fragment
可以類似一個控件來使用,只不過在
android:name="wedfrend.wang.privateproject.fragment.FirstFragment"
在這個屬性中一定要明確的指示出來你所創建的類:包名+類名
看看效果:
各方法的執行順序
點擊返回按鈕
之後我們便可以進行邏輯上的操作在各個方法中。
2 :動態的加載Fragment,我們知道Fragment相當於一個UI,要動態的加載Fragment我們需要一個容器,所以我們現在將上述的Activity的佈局修改:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="wedfrend.wang.privateproject.recycle.FragmentActivity">
<FrameLayout
android:id="@+id/frame_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:padding="10dp"
android:background="@android:color/darker_gray">
<Button
android:id="@+id/btn_firstFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/holo_green_dark"
android:textSize="15sp"
android:layout_marginRight="5dp"
android:text="First"
/>
<Button
android:id="@+id/btn_secondFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/holo_green_dark"
android:textSize="15sp"
android:layout_marginLeft="5dp"
android:text="Second"
/>
</LinearLayout>
</RelativeLayout>
我們添加一個FrameLayout來作爲Fragment的容器。
動態的加載Fragment的步驟:
/**
* 說明:
*
* 動態添加碎片5個步驟
*
* 1.創建待添加碎片的實例
*
* 2.獲取FragmentManager實例,在活動中通過getSupportFragmentManager()方法獲取
*
* 3.開啓一個事務,通過調用 beginTransaction()方法開啓
*
* 4.向容器內添加或者替換碎片,使用replace()方式
*
* 5.提交事務,使用commit()完成
*
*
*
* 對於第4點,這裏進行補充,FragmentTransaction提供操作碎片的方法中有
*
* add(),hide(),show(),remove(),replace();
*
* 在實際的項目中,具體使用那些方式需要你根據實際的情況進行考慮,代碼如下,可以理解爲replace是remove()和add()的結合
*/
public void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_fragment,fragment);
fragmentTransaction.commit();
}
那我們現在的佈局中有兩個Button,代碼的需求是,現在需要點擊第一個button,FrameLayout顯示FirstFragment,點擊第二個Button,顯示第二個SectondFragment.
那我們看看代碼,現在有兩個Button,實例化和點擊方法就不說了,現在看看如何使用,創建方法
//i = 0:FirstFragment
//i = 1:SecondFragment
//目前使用的是add,hide,和show的方法進行結合使用
public void setFragment(int i){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if(firstFragment != null){
fragmentTransaction.hide(firstFragment);
}
if(secondFragment != null){
fragmentTransaction.hide(secondFragment);
}
switch (i){
case 0:
if(firstFragment == null){
firstFragment = new FirstFragment();
fragmentTransaction.add(R.id.frame_fragment,firstFragment);
}else{
fragmentTransaction.show(firstFragment);
}
break;
case 1:
if(secondFragment == null){
secondFragment = new SecondFragment();
fragmentTransaction.add(R.id.frame_fragment,secondFragment);
}else{
fragmentTransaction.show(secondFragment);
}
break;
}
// fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
SecondFragment的方法和FirstFragment一致,只是佈局顯示不同。(略)
Button1的點擊方法:
setFragment(0);
button2的點擊方法
setFragment(1);
看看結果:
點擊Button1:
點擊Button2
因爲我現在使用的add(),hide()和show()方法進行Fragment的顯示與隱藏。
所以我麼點擊Button2的時候FirstFragment只是進行了隱藏,當我們在點擊Button1的時候對於FirstFragment沒有什麼方法的調用。
點擊手機的back按鈕,結果
現在換一種顯示方式,我們將add(),hide(),show()方法替換爲replace()方法:修改容易,將
Button1的點擊方法改爲
replaceFragment(new FirstFragment());
Button2的點擊方法改爲
replaceFragment(new SecondFragment());
看看執行效果
點擊Button1
點擊Button2
調用replace()方法,對於FirstFragment就進行了銷燬,當你在點擊Button1的時候,SecondFragment同樣也是被銷燬的。
點擊返回按鈕
對於上述的顯示方法進行實踐後,可以發現兩種加載Fragment的方式對於程序的書寫方法需要 注意的地方還是有區別的。
但是 我們點擊back按鈕的時候,加載Fragment的Activity是跟着一起退出的,那麼我們有什麼辦法使得Fragment的加載像棧一致,點擊一次back按鈕判斷如果Activity中有兩個Fragment,那麼也像Activity一樣,點擊一次退出一個Fragment。
那就要看看下面的這個方法:調用FragmentTransaction中addToBackStack()方法。注意一定要在commit()方法之前進行調用
如下:
public void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_fragment,fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
現在我們再看看執行調用的方法:
點擊Button1
點擊Button2:
仔細的觀察:添加了fragmentTransaction.addToBackStack(null);
方法之後,在點擊Button2的時候,FirstFragment的onDetach()
方法並沒有執行,所以此時的FirstFragment與Activity並沒有解除綁定關係。再次點擊Button1看看
所以,此時還是要執行onAttach()方法的。
現在我們的Fragment有三個了,分別是:
FirstFragment—SecondFragment—FirstFirgment
第一次back:
第二次back
第三次back
此時每點擊一次back,退出一次Fragment,是否跟Activity的standard的啓動模式類似?
Activity和Fragment兩者之間的關係已經整理完成,有沒有感覺對兩者之間的理解更加了然於胸?
Activity和Fragment之間的通信
有時候我們需要在Fragment與Activity之間進行通信
1:靜態的綁定情況下:
Activity獲取Fragment的方法:
FragnentManager提供一個類似於findViewById()的方法,專門用於從佈局文件中獲取碎片的實例
SecondFragment sf = (SecondFragment)getFragmentManager().findFragmentById(R,id.xxxx);
2.動態綁定的情況下,你需要實例化Fragment,這樣的話就和普通類的調用方法一致了
Fragment獲取Activity的方法:
在每個碎片中都可以通過調用getActicity()方法來得到當前碎片相關聯的活動實例:
FragmentActivity activity = (FragmentActivity) getActivity();
使用限定符
一般情況下,android系統會根據屏幕的實際情況獲取你的手機或者平板來加載相應的佈局。
所以你只需要在res目錄下創建一個layout-large的文件夾,將你的佈局寫入就好。
另外有一個最小限定符:
larger有多大?有時候我們就想當設備的寬度大於600的時候就加載類似平板的佈局怎麼辦?
只需要創建 res/layout-sw600dp文件夾就好,將相應的佈局放入,這樣系統在寬度大於600的時候會自動加載相應的佈局。
android中一些常見的限定符:
注:圖片來源:第一行代碼第二版(郭霖著)p158-p159
實例:一個簡易的列表實踐,適配平板,手機