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

 

 

如果有什么错误,或者我理解错误或不当的,恳请大家纠正,谢谢!嘻嘻嘻

posted on 2017-03-10 10:51  艹艹哒丶  阅读(4108)  评论(0编辑  收藏  举报

导航