android基础知识之 - Fragment
1.1 碎片的简单用法
需求:
- 在一个Activity当中添加两个碎片,并让这两个碎片平分活动空间
最终视图:
源码:
新建一个左侧Fragment布局left_fragment.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Button"
/>
</LinearLayout>
- 图示:
这个布局中放置了一个Button,并让它水平居中显示
- 新建右侧Fragment布局right_fragment.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="This is right fragment"
/>
</LinearLayout>
- 图示:
这个布局的背景颜色设置成了绿色,并放置了一个TextView用于显示一段文本
- 新建一个LeftFragment类,并让它继承自Fragment,这里选择继承support-v4库,另外我们不需要再build.gradle文件中添加support-v4库的依赖,因为build.gradle文件中已经添加了appcompat-v7库的依赖,而这个库会将support-v4库也一起引入进来
LeftFragment :
public class LeftFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragment, container, false);
return view;
}
}
重写Fragment的onCreateView()方法,然后在这个方法中通过LayoutInflater的inflate()方法将刚才定义的left_fragment布局动态加载进来
- 用同样的方法新建RightFragment :
public class RightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.right_fragment, container, false);
return view;
}
}
- 接下来修改activity_main.xml中的代码,将LeftFragment和RightFragment加载进activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/right_fragment"
android:name="com.example.fragmenttest.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
可以看到使用标签在布局中添加碎片,这里通过android:name属性来显示指明要添加的碎片类名,注意一定要将类的包名也加上
- 最终效果:
两个Fragment平分整个活动的布局
1.2 动态添加碎片
- 效果图:
Fragment真正强大之在于,它可以在程序运行时动态地添加到活动中
- 在1.1的基础上修改源码
- 新建another_right_fragment.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#ffff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="This is another right fragment"
/>
</LinearLayout>
这个布局和right_frgment.xml中的代码基本相同,只是将背景色改成黄色,并修改了显示的文字
- 新建AnotherRightFragment作为另一个右侧碎片 :
public class AnotherRightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_right_fragment, container, false);
return view;
}
}
同样是在onCreateView()方法中加载了刚刚创建的another_right_fragment布局
- 准备好另一个Fragment之后,就来看一下如果将它动态地添加到活动中,修改activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
// 新增布局
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
可以看到,现在将右侧碎片替换成了一个FrameLayout,下面我们将在代码中想FrameLayout里添加内容,从而实现动态添加碎片的功能,修改MainActivity中的代码 :
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
replaceFragment(new RightFragment());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
replaceFragment(new AnotherRightFragment());
break;
default:
break;
}
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout, fragment);
transaction.commit();
}
}
可以看到,首先我们给左侧Fragment中的按钮注册了一个点击事件,然后调用replaceFragment()方法动态添加了RightFragment这个碎片,当点击左侧碎片中的按钮时,又会调用replaceFragment()方法将右侧碎片替换成AnotherRightFragment,结合replaceFragment()方法中的代码可以看出,动态添加Fragment主要分为5步:
- 创建待添加的碎片实例。这里是RightFragment()和AnotherRightFragment()
- 获取FragmentManager,在Activity中可以直接通过调用getSupportFragmentManager()方法得到
- 开启一个事务,通过调用FragmentManager的beginTransaction()方法开启
- 向容器内添加或替换Fragment,一般使用replace()方法实现,需要传入容器的id和待添加的Fragment实例
提交事务,调用commit()方法来完成
这样就完成了在活动中动态添加碎片的功能- 最终效果:
- 最终效果:
可以看到,通过点击按钮添加了一个碎片之后,这时按下Back键程序就会直接退出
1.3 在碎片中模拟返回栈
- 添加返回栈效果:
1.2中通过点击按钮添加了一个碎片之后,这时按下Back键程序就会直接退出,如果这里我们要模拟返回栈的效果,按下Back键可以回到上一个碎片,要实现这种效果其实很简单,FragmentTransaction中提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中,修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
...
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout, fragment);
// 添加
transaction.addToBackStack(null);
transaction.commit();
}
}
在这里我们在事务提交之前条用了FragmentTransaction的addToBackStack()方法,它可以接受一个名字用于描述返回栈的状态,一般传入null即可
- 最终效果:
1.4 Fragment和Activity之间进行通信
虽然Fragment都是嵌入在Activity中显示的,可是实际上它们之间的关系并没有那么亲密,可以看出Fragment和Activity都是各自存在于一个独立的类当中的,它们之间并没有那么明显的方式来直接进行通信,如果想要在Activity中调用Fragment的方法,或者在Fragment中调用Activity方法,应该如何实现?
为了方便Fragment和Activity之间进行通信,FragmentManager提供了一个findFragmentById()的方法,专门用于从布局文件中获取碎片的实例:
NewsContentFragment newsContentFragment = (NewsContentFragment)getFragmentManager().findFragmentById(R.id.news_content_fragment);
调用FragmentManager的findFragmentById()方法,可以在Activity中得到相应Fragment的实例,然后就可以轻松地调用Fragment里面的方法了
那么Fragment又是怎样调用Activity里面的方法呢?在每个Fragment中都可以通过getActivity()方法来得到和当前Fragment相关联的Activity实例:
MainActivity activity = (MainActivity)getActivity();
有了Activity实例后,在Fragment中调用Activity里的方法就变得轻而易举了,当碎片中需要使用Context对象时,也可以使用getActivity()方法,因为获得的Activity本身就是个Context对象
那么Fragment与Fragment之间如何进行通信呢?
首先在Fragment中可以得到与它相关联的Activity,然后再通过这个Activity去获取另外一个Fragment的实例,这样也就实现了不同Fragment之间的通信功能
1.5 Fragment的生命周期
和Activity一样,Fragment也有自己的生命周期,理解Fragment的生命周期非常重要,我们通过代码的方式来瞧一瞧Fragment的生命周期是什么样的:
public class Fragment1 extends Fragment {
public static final String TAG = "Fragment1";
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d(TAG, "onAttach");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
return inflater.inflate(R.layout.fragment1, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated");
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "onDetach");
}
}
可以看到,上面的代码在每个生命周期的方法里都打印了日志,然后我们来运行一下程序,可以看到打印日志如下:
这时点击一下home键,打印日志如下:
如果你再重新进入进入程序,打印日志如下:
然后点击back键退出程序,打印日志如下:
看到这里,我相信大多数朋友已经非常明白了,因为这和Activity的生命周期太相似了。只是有几个Activity中没有的新方法,这里需要重点介绍一下:
- onAttach方法:Fragment和Activity建立关联的时候调用。
- onCreateView方法:为Fragment加载布局时调用。
- onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
- onDestroyView方法:Fragment中的布局被移除时调用。
- onDetach方法:Fragment和Activity解除关联的时候调用。
参考:
Android Fragment完全解析,关于碎片你所需知道的一切
https://blog.csdn.net/guolin_blog/article/details/8881711