Android之Fragment回退棧詳解
阿新 • • 發佈:2019-02-07
前言:本文將結合開發中的實際需求,來講解一下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();
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 判斷當前按鍵是返回鍵
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 獲取當前回退棧中的Fragment個數
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
// 判斷當前回退棧中的fragment個數,
if (backStackEntryCount > 1) {
// 立即回退一步
fragmentManager.popBackStackImmediate();
// 獲取當前退到了哪一個Fragment上,重新獲取當前的Fragment回退棧中的個數
BackStackEntry backStack = fragmentManager
.getBackStackEntryAt(fragmentManager
.getBackStackEntryCount() - 1);
// 獲取當前棧頂的Fragment的標記值
String tag = backStack.getName();
// 判斷當前是哪一個標記
if ("fragment1".equals(tag)) {
// 設定首頁選中
rb_home.setChecked(true);
} else if ("fragment2".equals(tag)) {
// 設定購物車的tag
rb_cart.setChecked(true);
} else if ("fragment3".equals(tag)) {
rb_category.setChecked(true);
} else if ("fragment4".equals(tag)) {
rb_personal.setChecked(true);
}
} else {
//回退棧中只剩一個時,退出應用
finish();
}
}
return true;
}
}
退出所有隻剩首頁而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;
}
}