Android之Fragment回退栈详解
前言:本文将结合开发中的实际需求,来讲解一下Fragment中的回退栈 对于Activity,当按返回键时,能够返回到上一个Activity,但是,当我们Fragment到Activity中时,如果不做任何处理,当按返回键时,当前Fragment都会全部退出,如果想要拥有Activity逐渐退出的效果,我们需要应用一下Fragment中的回退栈.
视频地址:
代码地址:
案例效果
案例描述
大家可以自行打开京东,你会发现,如果你点击了分类,发现,购物车,我的,按钮,再按返回键的话,会先回到首页,然后再退出应用.这里应用的就是Fragment的回退栈功能.,下面我将带领大家了解一下回退栈的实现逻辑
方法介绍
- addToBackStack(tag); 将Fragment添加到回退栈中
- popBackStack(); 清除回退栈中栈顶的Fragment
- popBackStack(String tag, int i );
- 如果i=0,回退到该tag所对应的Fragment层
- 如果i=FragmentManager.POP_BACK_STACK_INCLUSIVE,回退到该tag所对应的Fragment的上一层
- popBackStackImmediate 立即清除回退栈中栈顶Fragment
- getBackStackEntryCount(); 获取回退栈中Fragment的个数
- getBackStackEntryAt(int index) 获取回退栈中该索引值下的Fragment
逐层退出回退栈效果代码实现
布局代码,在布局中,写了一个FrameLayout,用来放置Fragment的容器;写了一个RadioGroup,用来放置下边的几个指示按钮
<LinearLayout 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"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/rb_home"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:button="@drawable/home_selector"
android:checked="true"
android:gravity="center_horizontal" />
<RadioButton
android:id="@+id/rb_cart"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@drawable/cart_selector" />
<RadioButton
android:id="@+id/rb_category"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@drawable/category_selector" />
<RadioButton
android:id="@+id/rb_personal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@drawable/personal_selector" />
</RadioGroup>
</LinearLayout>
</LinearLayout>
MainActivity中的代码
- 初始化,在onCreate方法中
- 初始化控件,并设置监听
- 添加一个HomeFragment
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
// 获取Fragment管理者
fragmentManager = getSupportFragmentManager();
// 先默认添加fragment1
addFragment(new Fragment1(), "fragment1");
}
- 初始化控件给RadioButton设置监听
private void initView() {
radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
rb_cart = (RadioButton) findViewById(R.id.rb_cart);
rb_category = (RadioButton) findViewById(R.id.rb_category);
rb_home = (RadioButton) findViewById(R.id.rb_home);
rb_personal = (RadioButton) findViewById(R.id.rb_personal);
// 对每一个RadioButton都设置点击事件,注意,在这里并没有对radioGroup设置checkChangeListener
rb_cart.setOnClickListener(this);
rb_category.setOnClickListener(this);
rb_home.setOnClickListener(this);
rb_personal.setOnClickListener(this);
}
*点击按钮时,替换Fragment
/**
* 根据点击的按钮---依次替换Fragment
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.rb_home:
addFragment(new Fragment1(), "fragment1");
break;
case R.id.rb_cart:
addFragment(new Fragment2(), "fragment2");
break;
case R.id.rb_category:
addFragment(new Fragment3(), "fragment3");
break;
case R.id.rb_personal:
addFragment(new Fragment4(), "fragment4");
break;
default:
break;
}
}
- 添加Fragment的时候,同时将Fragment放到回退栈中
public void addFragment(Fragment fragment, String tag) {
// 开启事务
FragmentTransaction beginTransaction = fragmentManager
.beginTransaction();
// 执行事务,添加Fragment
beginTransaction.add(R.id.framelayout, fragment, tag);
// 添加到回退栈,并定义标记
beginTransaction.addToBackStack(tag);
// 提交事务
beginTransaction.commit();
}
- 监听Activity中的返回键,判断当前回退栈中的Fragment个数,如果回退栈中有大于一个,就一个个清除Fragment,如果只剩一个,说明只剩首页Fragment所对应的Fragment,就finish();
退出所有只剩首页而Fragment的代码
其他代码和上边一致,只需要修改一下退出的逻辑.需要判断当前回退栈中有多少个Fragment,使用While循环逐个退出.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 判断当前按键是返回键
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 获取当前回退栈中的Fragment个数
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
// 回退栈中至少有多个fragment,栈底部是首页
if (backStackEntryCount > 1) {
// 如果回退栈中Fragment个数大于一.一直退出
while (fragmentManager.getBackStackEntryCount() > 1) {
fragmentManager.popBackStackImmediate();
//选中第一个界面
rb_home.setChecked(true);
}
} else {
finish();
}
}
return true;
}
}