一:介绍:碎片(Fragment)是一种可以嵌入在活动(Activity)当中的 UI 片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。它和活动实在是太像了,同样都能包含布局,同样都有自己的生命周期。你甚至可以将碎片理解成一个迷你型的活动,虽然这个迷你型的活动有可能和普通的活动是一样大的。—— 摘抄自《Android第一行代码》
二:生命周期:如下图
与Activity不同的方法:
onAttach():与Activity发生关联是被调用
onCreateView():初始化Fragment布局的时候会被调用
onActivityCreate():当Activity的onCreate方法返回时调用
onDestoryView():当该Fragment的视图被移除时调用
onDetach():当Fragment与Activity关联被取消时调用
三:用途:①:模块化由于Fragment 可以嵌套在Activity中,并可以运用添加、替换、移除Fragment等操作对Fragment的视图布局进行显示与隐藏。所以,在一个业务模块中,采用单Activity多个Fragment的布局结构,可以方便管理,并且减轻布局的层级绘制以及性能优化。
四:使用:
1.静态使用Fragment(虽然在平时项目中基本没有这样使用过)
要点:
①:使用< fragment></ fragment>标签
②:使用name: fragment类所在的名称
ShowOneActivity.java
package com.example.fragmentlearn;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class ShowOneActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_one);
}
}
activity_show_one.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmentlearn.ShowOneActivity">
<fragment
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.fragmentlearn.FragmentOne"
/>
</android.support.constraint.ConstraintLayout>
2.动态使用Fragment
①:常用API:
android.support.v4.app.FragmentManager:用于操作Fragment
android.support.v4.app.FragmentTransaction:保证操作Fragment的原子性
②:获取FragmentManager()
在Activity中:FragmentManager fm = getSupportFragmentManager()
在Fragment中:FragmentManager fm = getChildFragmentManager()
而不是getFragmentManager()。
③:通过Trasaction操作Fragment的添加、替换、移除、显示、隐藏、关联、解除关联。
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add():
向Activity中添加一个Fragment.
transaction.remove():
从Activity中移除一个Fragment,如果这个Fragment没有被添加到回退栈,则会销毁实例。(此操作会 销毁视图、销毁实例)
transaction.replace():
将Fragment替换为另一个Fragment,是remove及add的合体操作.(此操作会 销毁视图、销毁实例)
transaction.attach():
将detach的fragment重新关联到视图上,与detach()对应
transaction.detach();
将Activity视图上的Fragment解除关联,但不销毁实例(此操作会 销毁视图,不销毁实例)
transaction.show();
显示之前隐藏的Fragment,与hide()对应
transaction.hide();
隐藏当前显示的Fragment (此操作不会 销毁视图、不销毁实例)
问题:当transaction.hide() 与transaction.detach()或者transaction.remove()的效果相同时,该如何进行选择呢?
答:此时,需要根据自己的业务场景,是否需要销毁视图或者实例来进行选择。
举例:例如需要保存用户的数据,使用transaction.hide(),比如控件EditText,当不销毁视图的时候,当用户填写内容后,再次显示的时候,EditText上填写的内容依然存在。但若不想保存用户的数据,则使用transaction.detach()或者transaction.remove(),再次显示的时候会重新创建视图,刚刚的内容也不会被保存。
这里需要注意,transaction.remove()则将实例也一并销毁,在显示的时候,需要重新new Fragment ()。而transaction.detach()则可以将实例放入回退栈中,下次通过fm.findViewByTag()进行取出。
使用案例:
简单案例一:动态显示Fragment
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmentlearn.MainActivity">
<FrameLayout
android:id="@+id/container_fl"
android:layout_width="match_parent"
android:layout_height="300dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/showFragmentOneBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="showOneFragment"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>
MainActivity.class
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private FragmentOne mFragmentOne;
private final String FRAG_ONE = "oneFragment";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
Log.i(TAG, "onCreate: ");
}
private void initView() {
Button showOneFragmentBtn = (Button) findViewById(R.id.showFragmentOneBtn);
showOneFragmentBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
mFragmentOne = new FragmentOne();
ft.add(R.id.container_fl,mFragmentOne,FRAG_ONE);
ft.commit();
}
});
}
FragmentOne.java
package com.example.fragmentlearn;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentOne extends BaseFragement {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, "onCreateView: ");
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
fragment_one.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmentlearn.FragmentOne">
<!-- TODO: Update blank fragment layout -->
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment One" />
</FrameLayout>
简单案例二:显示及隐藏Fragment:
FragmentOne的生命周期:当隐藏的时候,并没有任何变化,因为视图并没有被销毁,显示时又重新显示。
07-28 15:08:36.603 2742-2742/com.example.fragmentlearn I/FragmentOne: onAttach:
07-28 15:08:36.603 2742-2742/com.example.fragmentlearn I/FragmentOne: onCreate:
07-28 15:08:36.603 2742-2742/com.example.fragmentlearn I/FragmentOne: onCreateView:
07-28 15:08:36.617 2742-2742/com.example.fragmentlearn I/FragmentOne: onActivityCreated:
07-28 15:08:36.617 2742-2742/com.example.fragmentlearn I/FragmentOne: onStart:
07-28 15:08:36.617 2742-2742/com.example.fragmentlearn I/FragmentOne: onResume:
showOneActivity.java
package com.example.fragmentlearn;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class ShowOneActivity extends AppCompatActivity implements View.OnClickListener {
private FragmentOne mFragmentOne;
private static final String FRAG_ONE = "fragmentOne";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_one);
initView();
}
private void initView() {
Button showBtn = (Button) findViewById(R.id.showFragmentBtn);
Button hideBtn = (Button) findViewById(R.id.hideFragmentBtn);
showBtn.setOnClickListener(this);
hideBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.showFragmentBtn:
if (mFragmentOne == null) {
mFragmentOne = new FragmentOne();
ft.add(R.id.container_fl, mFragmentOne, FRAG_ONE);
} else {
ft.show(mFragmentOne);
}
break;
case R.id.hideFragmentBtn:
if (mFragmentOne != null && mFragmentOne.isAdded()) {
ft.hide(mFragmentOne);
}
break;
default:
}
ft.commit();
}
}
activity_show_one.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmentlearn.ShowOneActivity">
<Button
android:id="@+id/showFragmentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="showOneFragment"
android:textAllCaps="false" />
<Button
android:id="@+id/hideFragmentBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/showFragmentBtn"
android:text="hideOneFragment"
android:textAllCaps="false" />
<FrameLayout
android:id="@+id/container_fl"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
FragmentOne.java
public class FragmentOne extends BaseFragement {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, " onCreateView: ");
status.append(TAG + " onCreateView");
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
fragment_one.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fragmentlearn.FragmentOne">
<!-- TODO: Update blank fragment layout -->
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment One" />
<EditText
android:hint="EditText"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
简单实例三:关联及解除关联Fragment
EditText中的View在进行重新关联的时候会清除已经填写的数据内容
attach:
07-28 15:18:47.599 9624-9624/com.example.fragmentlearn I/FragmentOne: onAttach:
07-28 15:18:47.599 9624-9624/com.example.fragmentlearn I/FragmentOne: onCreate:
07-28 15:18:47.599 9624-9624/com.example.fragmentlearn I/FragmentOne: onCreateView:
07-28 15:18:47.602 9624-9624/com.example.fragmentlearn I/FragmentOne: onActivityCreated:
07-28 15:18:47.602 9624-9624/com.example.fragmentlearn I/FragmentOne: onStart:
07-28 15:18:47.602 9624-9624/com.example.fragmentlearn I/FragmentOne:
detach:
07-28 15:18:48.439 9624-9624/com.example.fragmentlearn I/FragmentOne: onPause:
07-28 15:18:48.439 9624-9624/com.example.fragmentlearn I/FragmentOne: onStop:
07-28 15:18:48.439 9624-9624/com.example.fragmentlearn I/FragmentOne: onDestroyView:
attach:
07-28 15:18:50.013 9624-9624/com.example.fragmentlearn I/FragmentOne: onCreateView:
07-28 15:18:50.019 9624-9624/com.example.fragmentlearn I/FragmentOne: onActivityCreated:
07-28 15:18:50.019 9624-9624/com.example.fragmentlearn I/FragmentOne: onStart:
07-28 15:18:50.019 9624-9624/com.example.fragmentlearn I/FragmentOne: onResume:
ShowOneActivity.java 更改部分:
switch (v.getId()) {
case R.id.showFragmentBtn:
if (mFragmentOne == null) {
mFragmentOne = new FragmentOne();
ft.add(R.id.container_fl, mFragmentOne, FRAG_ONE);
} else {
ft.attach(mFragmentOne);
}
break;
case R.id.hideFragmentBtn:
if (mFragmentOne != null && mFragmentOne.isAdded()) {
ft.detach(mFragmentOne);
}
break;
default:
简单案例四:add remove Fragment
add:
07-28 15:27:11.728 18594-18594/com.example.fragmentlearn I/FragmentOne: onAttach:
07-28 15:27:11.728 18594-18594/com.example.fragmentlearn I/FragmentOne: onCreate:
07-28 15:27:11.728 18594-18594/com.example.fragmentlearn I/FragmentOne: onCreateView:
07-28 15:27:11.737 18594-18594/com.example.fragmentlearn I/FragmentOne: onActivityCreated:
07-28 15:27:11.737 18594-18594/com.example.fragmentlearn I/FragmentOne: onStart:
07-28 15:27:11.737 18594-18594/com.example.fragmentlearn I/FragmentOne: onResume:
remove:
07-28 15:27:12.702 18594-18594/com.example.fragmentlearn I/FragmentOne: onPause:
07-28 15:27:12.702 18594-18594/com.example.fragmentlearn I/FragmentOne: onStop:
07-28 15:27:12.702 18594-18594/com.example.fragmentlearn I/FragmentOne: onDestroyView:
07-28 15:27:12.702 18594-18594/com.example.fragmentlearn I/FragmentOne: onDestroy:
07-28 15:27:12.702 18594-18594/com.example.fragmentlearn I/FragmentOne: onDetach:
ShowOneActivity.java 更改部分
case R.id.showFragmentBtn:
if (mFragmentOne == null) {
mFragmentOne = new FragmentOne();
}
ft.add(R.id.container_fl, mFragmentOne, FRAG_ONE);
break;
case R.id.hideFragmentBtn:
if (mFragmentOne == null) {
mFragmentOne = new FragmentOne();
}
ft.remove(mFragmentOne);
break;
default:
简单案例五:简单封装显示Fragment
private BaseFragment mPreFragment;
public void showFragment(int resId, BaseFragment curFragment, String curFragmentTag) {
FragmentManager fm = getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (fm.findFragmentByTag(curFragmentTag) == null) {
ft.add(resId, curFragment, curFragmentTag);
Logger.d(Logger._JN, "add ");
}
if (mPreFragment != null && mPreFragment.isVisible()) {
ft.hide(mPreFragment);
Logger.d(Logger._JN, "hide ");
}
ft.show(curFragment);
mPreFragment = curFragment;
ft.commit();
}
使用:
private void initView() {
mFragmentOne = new FragmentOne();
mFragmentTwo = new FragmentTwo();
}
switch (v.getId()) {
case R.id.showFragmentOneBtn:
showFragment(R.id.container_fl,mFragmentTwo,mFragmentOne,FRAG_ONE);
break;
case R.id.showFragmentTwoBtn:
showFragment(R.id.container_fl,mFragmentOne,mFragmentTwo,FRAG_TWO);
break;
default:
}
回退栈介绍
介绍:类似于Activity,当用户在点击后退键时,系统会将Activity保存起来,Fragment也有这种功能,不过我们要显示的调用addToBackStack()方法进行保存。
用途:保留Fragment的实例,当按返回键的时候,可以返回到上一个添加到回退栈中的Fragment中。