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
效果是一模一样的。
这种方法叫静态加载。
所以当然我们也可以和之前自定义控件一样,再Activity中实现自定义控件里面的小控件的响应事件,用
还可以在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 2是这样的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
1 23 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
相当与一个祯布局。
好,让我们回到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对象。
如果有什么错误,或者我理解错误或不当的,恳请大家纠正,谢谢!嘻嘻嘻