转:https://www.cnblogs.com/purediy/p/3276545.html
转:https://blog.csdn.net/ash_zheng/article/details/5140535
Fragment一般是宿主Activity UI的一部分或一种行为,作为Activity的整个View Hierarchy的一部分嵌入。我们可以将多个Fragment组合到一个Activity中创建一个多面界面,也可以在多个Activity中重用一个Fragment。
Fragment概述
我们可以把Fragment视为模块化的一段Activity,它具有自己的生命周期,接收它自己的事件,并可以在activity运行时被添加或删除。
Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。
例如:当activity暂停时,它拥有的所有的Fragment们都暂停了,当activity销毁时,它拥有的所有Fragment们都被销毁。然而,当activity运行时(在onResume()之后,onPause()之前),你可以单独地操作每个Fragment,比如添加或删除它们。当你在执行上述针对Fragment的事务时,你可以将事务添加到一个棧中,这个栈被activity管理,栈中的每一条都是一个Fragment的一次事务。有了这个栈,就可以反向执行Fragment的事务,这样就可以在Fragment级支持“返回”键(向后导航)。
当向activity中添加一个Fragment时,它须置于ViewGroup控件中,并且需定义Fragment自己的界面。你可以在layoutxml文件中声明Fragment,元素为:<fragment>;也可以在代码中创建Fragment,然后把它加入到ViewGroup控件中。然而,Fragment不一定非要放在activity的界面中,它可以隐藏在后台为actvitiy工作。
如何使用Fragment
接下来讲如何使用fragment,包括fragment在加入activity的后退棧中时如何保持自己的状态,如何与activity以及其它fragment们共享事件,如何显示在activity的动作栏,等等。
Android从3.0开始引入fragment,主要是为了支持更动态更灵活的界面设计,比如在平板上的应用。平板机上拥有比手机更大的屏幕空间来组合和交互界面组件们。Fragment使你在做那样的设计时,不需应付view树中复杂的变化。通过把activity的layout分成fragment,你可以在activity运行时改变它的样子,并且可以在activity的后退栈中保存这些改变。
例如:写一个读新闻的程序,可以用一个fragment显示标题列表,另一个fragment显示选中标题的内容,这两个fragment都在一个activity上,并排显示。那么这两个fragment都有自己的生命周期并响应自己感兴趣的事件。于是,不需再像手机上那样用一个activity显示标题列表,用另一个activity显示新闻内容;现在可以把两者放在一个activity上同时显示出来。如下图:
Fragment必须被写成可重用的模块。因为fragment有自己的layout,自己进行事件响应,拥有自己的生命周期和行为,所以你可以在多个activity中包含同一个Fragment的不同实例。这对于让你的界面在不同的屏幕尺寸下都能给用户完美的体验尤其重要。比如你可以在程序运行于大屏幕中时启动包含很多fragment的activity,而在运行于小屏幕时启动一个包含少量fragment的activity。
举个例子--还是刚才那个读新闻的程序-当你检测到程序运行于大屏幕时,启动activityA,你将标题列表和新闻内容这两个fragment都放在activityA中;当检测到程序运行于小屏幕时,还是启动activityA,但此时A中只有标题列表fragment,当选中一个标题时,activityA启动activityB,B中含有新闻内容fragment。
两种方式加入Fragment
首先创建 Demo3Fragment 继承 Fragment 类, 并为其创建xml布局文件fragment_demo3.xml
package com.ashzheng.studydemo.demo3;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ashzheng.studydemo.R;
public class Demo3Fragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//(你要加载的布局,viewGrounp,是否附件到布局文件的根视图)
View view = inflater.inflate(R.layout.fragment_demo3, container, false);
return view;
}
}
MainActivity.java中
//按钮点击弹出fragment
public void fragmentDemo(View view){
startActivity(new Intent(this,Demo3Fragment.class));
}
1. 通过XML标签
在activity的fragment_demo3.xml布局文件中添加节点
<fragment
android:id="@+id/demo3_fg"
android:name="com.ashzheng.studydemo.demo3.Demo3Fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fragment的基本使用"
android:onClick="fragmentDemo"/>
2. 通过代码动态创建
-
新建一个xml布局fragment_demo4.xml,并绑定到一个新的Activity中(Demo3Activity),此布xml布局文件中添加容器视图(可以是任意的ViewGroup),用来装fragment
-
设置一个Button用来实现动态添加效果
-
<FrameLayout android:id="@+id/demo3_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="add" android:onClick="add"/>
-
在activity中动态添加fragment
package com.ashzheng.studydemo.demo3; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import com.ashzheng.studydemo.R; public class Demo3Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo3); } //给按键添加点击事件,每次点击添加一个fragment到容器里面去 public void add(View view){ FragmentManager fragmentManager = getFragmentManager(); //通过fragmentManager对象去开启一个事务 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //要将fragment添加到哪个容器ViewGroup中去,装fragment的具体对象 fragmentTransaction.add(R.id.demo3_layout, new Demo3Fragment()); fragmentTransaction.commit();//将操作提交 } }
5. 在activity中动态remove移除fragment
private FragmentManager mfragmentManager;
//移除fragment操作
public void remove(View view){
mfragmentManager = getFragmentManager();
//通过fragmentManager对象去开启一个事务
FragmentTransaction mfragmentTransaction = mfragmentManager.beginTransaction();
//remove有两种一个根据findFragmentById 容器的id 另一种是findFragmentByTag
//在add方法中有第三个参数就是Tag
fragmentTransaction.remove(mfragmentTransaction.findFragmentByTag("fragment"));
fragmentTransaction.commit();//将操作提交
}
替换(replace)fragment操作
public void replace(View view){
//通过fragmentManager对象去开启一个事务
mfragmentTransaction = fragmentManager.beginTransaction();
//要将fragment添加到哪个容器ViewGroup中去,装你要替换的新的fragment的具体对象
fragmentTransaction.replace(R.id.demo3_layout, new AnotherDemo3Fragment());
fragmentTransaction.commit();//将操作提交
}
fragment隐藏(hide)和显示(show)操作 :
public void hide(View view){
//通过fragmentManager对象去开启一个事务
mfragmentTransaction = fragmentManager.beginTransaction();
//mfragmentTransaction查找你原先带Tag的fragment进行隐藏
fragmentTransaction.hide(mfragmentTransaction.findFragmentByTag("fragment"));
fragmentTransaction.commit();//将操作提交
}
public void show(View view){
//通过fragmentManager对象去开启一个事务
mfragmentTransaction = fragmentManager.beginTransaction();
//mfragmentTransaction查找你原先带Tag的fragment进行显示
fragmentTransaction.show(mfragmentTransaction.findFragmentByTag("fragment"));
fragmentTransaction.commit();//将操作提交
}
Fragment的传值
新建一个Fragment1.java和fragment1_activity.xml用来做第一个fragment
Fragment1中实现在EditText中输入数据,点击Button进行传输到第二个界面TextView中
public class Fragment1 extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment1_activity,container,false);
Button bt=view.findViewById(R.id.fragment1_bt);
final EditText et=view.findViewById(R.id.fragment1_et);
//添加监听事件
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//新建Fragment对象
Fragment2 fragment2=new Fragment2();
Bundle bundle=new Bundle();
bundle.putString("data",et.getText().toString());
fragment2.setArguments(bundle);//传递数据
//点击后替换掉原来的fragment
getFragmentManager().beginTransaction().replace(R.id.fragment_viewGroup,fragment2).commit();
}
});
return view;
}
}
Fragment2.java和fragment2_activity.xml
public class Fragment2 extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment2_activity,container,false);
TextView tv=view.findViewById(R.id.fragment2_tv);
tv.setText(getArguments().getString("data"));//通过key值获取从Fragment1传来的数据
return view;
}
}
点击弹出第一个Fragment,用fragment_viewGroup作为container容器,来装Fragment1,展示第一个Fragment
//点击传递按钮弹出第一个fragment
public void send(View view){
getFragmentManager().beginTransaction().add(R.id.fragment_viewGroup,new Fragment1()).commit();
效果图
Fragment使用接口回调实现两个fragment在同一个Activity中传值
- 首先,创建两个Fragment(Fragment3、Fragment4)类继承Fragment,并绑定相应的xml文件
- 在主界面的xml布局文件中,直接用xml的方式添加两个fragment
- 实现功能:Fragment3中的xml文件有三个Button,Fragment4中有1个textview显示Fragment点击按钮后的相应按钮内容
使用接口回调的原因:为了不想Fragment3和Fragment4有相互的耦合
- Fragment3想控制Fragment4的textview显示内容,不是直接控制,而是将这个请求发送给主界面Activity
- 然后主界面将这个请求转发给Fragment4去设置textview设置文字;这样的发送请求和请求转发是通过接口回调来实现的
- 在Fragment4中有独立的显示文字的方法
- 在Fragment3中在通过onAattch()方法将Activity初始化的时候就与Fragment3进行绑定
- 在主界面Activity中获取Fragment4对象并调用它的独立方法,实现设置Fragment4要显示的文字。
- 简单的来说:Fragment3和Fragment4各自做各自的事情,由Activity进行请求转发。
FragmentValues3.java
public class FragmentValues3 extends Fragment implements View.OnClickListener{
private IButton mIButton;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment3, container, false);
Button button1 = (Button) view.findViewById(R.id.btn_1);
Button button2 = (Button) view.findViewById(R.id.btn_2);
Button button3 = (Button) view.findViewById(R.id.btn_3);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mIButton = (IButton) context;//初始化就绑定Fragment4
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
mIButton.onFragmentBtnClick(((Button) v).getText().toString());
}
}
FragmentValue4.java
public class FragmentValues4 extends Fragment {
TextView mTextView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment4, container, false);
mTextView = (TextView) view.findViewById(R.id.tv_value);
return view;
}
public void setFragmentTextValue(String textValue) {
mTextView.setText(textValue);
}
}
在主界面的xml布局文件中直接添加fragment布局。省略fragment3.xml和fragment4.xml的代码
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--id不可省略--->
<fragment
android:id="@+id/frg3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.imooc.fragmentdemo.FragmentValues3"
tools:layout="@layout/fragment3"/>
<fragment
android:id="@+id/frg4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.imooc.fragmentdemo.FragmentValues4"
tools:layout="@layout/fragment4"/>
</LinearLayout>
创建一个接口IButton.java
public interface IButton {
void onFragmentBtnClick(String text);
}
在主界面中实现这个接口,并获取FragmentValue4的对象调用设置tv的文字的方法
ublic class FragmentValueActivity extends AppCompatActivity implements IButton{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_value);
getSupportFragmentManager().beginTransaction().add(R.id.container, new FragmentValues1()).commit();
}
@Override
public void onFragmentBtnClick(String text) {
FragmentValues4 fragmentValues4 = (FragmentValues4) getSupportFragmentManager().findFragmentById(R.id.frg4);
fragmentValues4.setFragmentTextValue(text);//调用FragmentValue4的方法设置文字
}
}
Fragment的生命周期
1. 当一个fragment被创建的时候,它会经历以下状态.
- onAttach()
- onCreate()
- onCreateView()
- onActivityCreated()
2. 当这个fragment对用户可见的时候,它会经历以下状态。
- onStart()
- onResume()
3. 当这个fragment进入“后台模式”的时候,它会经历以下状态。
- onPause()
- onStop()
4. 当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。
- onPause()
- onStop()
- onDestroyView()
- onDestroy() // 本来漏掉类这个回调,感谢xiangxue336提出。
- onDetach()
5. 就像activitie一样,在以下的状态中,可以使用Bundle对象保存一个fragment的对象。
- onCreate()
- onCreateView()
- onActivityCreated()
6. fragments的大部分状态都和activitie很相似,但fragment有一些新的状态。
- onAttached() —— 当fragment被加入到activity时调用(在这个方法中可以获得所在的activity)。
- onCreateView() —— 当activity要得到fragment的layout时,调用此方法,fragment在其中创建自己的layout(界面)。
- onActivityCreated() —— 当activity的onCreated()方法返回后调用此方法
- onDestroyView() —— 当fragment中的视图被移除的时候,调用这个方法。
- onDetach() —— 当fragment和activity分离的时候,调用这个方法。
一旦activity进入resumed状态(也就是running状态),你就可以自由地添加和删除fragment了。因此,只有当activity在resumed状态时,fragment的生命周期才能独立的运转,其它时候是依赖于activity的生命周期变化的。