Fragment(優化布局)


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對象。

 

 

如果有什么錯誤,或者我理解錯誤或不當的,懇請大家糾正,謝謝!嘻嘻嘻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM