Android Studio - 带回栈的导航抽屉
Posted
技术标签:
【中文标题】Android Studio - 带回栈的导航抽屉【英文标题】:Android Studio - Navigation drawer with back stack 【发布时间】:2020-12-11 14:06:00 【问题描述】:我有一个导航抽屉活动,我想使用后退按钮:当我使用导航抽屉打开一个新片段时,如果用户按下后退按钮,我想返回到前一个片段。
如何使用后台堆栈?
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
// initDataTags();
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
...
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextColor(getColor(R.color.white));
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home,
R.id.nav_favourites,
R.id.nav_profile,
R.id.nav_login,
R.id.nav_register,
R.id.nav_cheats,
R.id.nav_puskak,
R.id.nav_settings,
R.id.nav_categories,
R.id.nav_act_category_item,
R.id.nav_act_item,
R.id.nav_library,
R.id.nav_video,
R.id.web_fragment,
R.id.nav_gdpr,
R.id.nav_selected_puska_fragment
)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
...
【问题讨论】:
【参考方案1】:我解决了这个问题。
我创造了自己的历史:
import java.util.ArrayList;
public class HistoryData
static ArrayList<String> history = new ArrayList<>();
static ArrayList<String> historyForward = new ArrayList<>();
private static final String TAG = "HistoryData";
public static String lastItem = "";
public static int actItem = 0;
public static void add(String item)
if(history.size() == 0)
history.add(item);
if (!item.equals(history.get(history.size() - 1)) && !lastItem.equals(item))
history.add(item);
actItem = history.size() - 1;
Log.d(TAG, "add: " + item);
for (int i = 0; i < history.size(); i++)
Log.d(TAG, "get: index(" + i + ") = " + history.get(i));
public static int size()
return history.size();
public static String get(int index)
Log.d(TAG, "get: " + history.get(index));
Log.d(TAG, "get: at index: " + index);
for (int i = 0; i < history.size(); i++)
Log.d(TAG, "get: index(" + i + ") = " + history.get(i));
return history.get(index);
public static String getLast()
return history.get(history.size() - 1);
public static String getPrev()
return history.get(history.size() - 2);
public static String remove(int index)
Log.d(TAG, "remove: " + history.get(index));
Log.d(TAG, "remove: at index: " + index);
historyForward.add(history.get(index));
actItem = history.size() - 1;
for (int i = 0; i < historyForward.size(); i++)
Log.d(TAG, "remove: hFw(" + i + ") = " + historyForward.get(i));
return history.remove(index);
public static int undoSize()
return historyForward.size();
public static String undo()
String result = historyForward.get(historyForward.size() - 1);
add(result);
historyForward.remove(historyForward.size() - 1);
for (int i = 0; i < historyForward.size(); i++)
Log.d(TAG, "undo: hFw(" + i + ") = " + historyForward.get(i));
return result;
我做了一个导航类
import android.util.Log;
import com.google.android.material.navigation.NavigationView;
import com.wecreatethefuture.puskapp.Activities.MainActivity;
import com.wecreatethefuture.puskapp.data.Constant;
import com.wecreatethefuture.puskapp.data.HistoryData;
public class Navigate
private static final String TAG = "Navigate";
public static void back()
MainActivity mainActivity = new MainActivity();
NavigationView navigationView = mainActivity.navPub();
Log.d(TAG, "handleOnBackPressed: HD size: " + HistoryData.size());
if (HistoryData.size() > 1)
String prev = HistoryData.getPrev();
Log.d(TAG, "handleOnBackPressed: prev: " + prev);
HistoryData.remove(HistoryData.size() - 1);
if(prev.equals(Constant.FRAGMENT_SETTING))
navigationView.getMenu().performIdentifierAction(R.id.nav_settings, 0);
else if(prev.equals(Constant.FRAGMENT_LIBRARY))
navigationView.getMenu().performIdentifierAction(R.id.nav_library, 0);
else if(prev.equals(Constant.FRAGMENT_GDPR))
navigationView.getMenu().performIdentifierAction(R.id.nav_gdpr, 0);
else if(prev.equals(Constant.FRAGMENT_FAVORITES))
navigationView.getMenu().performIdentifierAction(R.id.nav_favourites, 0);
else if(prev.equals(Constant.FRAGMENT_VIDEOS))
navigationView.getMenu().performIdentifierAction(R.id.nav_video, 0);
else if(prev.equals(Constant.FRAGMENT_CATEGORIES))
navigationView.getMenu().performIdentifierAction(R.id.nav_categories, 0);
else if(prev.equals(Constant.FRAGMENT_CHEATS))
navigationView.getMenu().performIdentifierAction(R.id.nav_cheats, 0);
else if(prev.equals(Constant.FRAGMENT_ACT_CATEGORY_ITEM))
navigationView.getMenu().performIdentifierAction(R.id.nav_act_category_item, 0);
else
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
else
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
public static void forward()
MainActivity mainActivity = new MainActivity();
NavigationView navigationView = mainActivity.navPub();
Log.d(TAG, "handleOnBackPressed: HD size: " + HistoryData.size());
if (HistoryData.undoSize() > 0)
String next = HistoryData.undo();
HistoryData.add(next);
if(next.equals(Constant.FRAGMENT_SETTING))
navigationView.getMenu().performIdentifierAction(R.id.nav_settings, 0);
else if(next.equals(Constant.FRAGMENT_LIBRARY))
navigationView.getMenu().performIdentifierAction(R.id.nav_library, 0);
else if(next.equals(Constant.FRAGMENT_GDPR))
navigationView.getMenu().performIdentifierAction(R.id.nav_gdpr, 0);
else if(next.equals(Constant.FRAGMENT_FAVORITES))
navigationView.getMenu().performIdentifierAction(R.id.nav_favourites, 0);
else if(next.equals(Constant.FRAGMENT_VIDEOS))
navigationView.getMenu().performIdentifierAction(R.id.nav_video, 0);
else if(next.equals(Constant.FRAGMENT_CATEGORIES))
navigationView.getMenu().performIdentifierAction(R.id.nav_categories, 0);
else if(next.equals(Constant.FRAGMENT_CHEATS))
navigationView.getMenu().performIdentifierAction(R.id.nav_cheats, 0);
else if(next.equals(Constant.FRAGMENT_ACT_CATEGORY_ITEM))
navigationView.getMenu().performIdentifierAction(R.id.nav_act_category_item, 0);
else
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
else
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
我在 Google 搜索后发现了一个 OnSwipeTouchListener
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class OnSwipeTouchListener implements View.OnTouchListener
private GestureDetector gestureDetector;
Context c;
public OnSwipeTouchListener(Context c)
gestureDetector = new GestureDetector(c, new GestureListener());
this.c = c;
public boolean onTouch(final View view, final MotionEvent motionEvent)
return gestureDetector.onTouchEvent(motionEvent);
private final class GestureListener extends
GestureDetector.SimpleOnGestureListener
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e)
return super.onDown(e);
@Override
public boolean onSingleTapUp(MotionEvent e)
onClick();
return super.onSingleTapUp(e);
@Override
public boolean onDoubleTap(MotionEvent e)
onDoubleClick();
return super.onDoubleTap(e);
@Override
public void onLongPress(MotionEvent e)
onLongClick();
super.onLongPress(e);
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
try
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY))
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD)
if (diffX > 0)
onSwipeRight();
else
onSwipeLeft();
catch (Exception exception)
exception.printStackTrace();
return false;
public void onSwipeRight()
Navigate.back();
public void onSwipeLeft()
Navigate.forward();
private void onClick()
private void onDoubleClick()
private void onLongClick()
最后我在 Fragments 中使用了它们,带有 OnBackPressed 事件和 onTouch 监听器(因为我也使用 swipe 来返回堆栈)
这是片段中的onCreate方法:
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
HistoryData.add(Constant.FRAGMENT_ACT_CATEGORY_ITEM);
OnBackPressedCallback callback = new OnBackPressedCallback(true)
@Override
public void handleOnBackPressed()
Navigate.back();
;
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
我将 OnSwieTouchListener 附加到我的视图中,例如:
ConstraintLayout constraintLayout = root_view.findViewById(R.id.constraintLayoutCategoryItemContainer);
constraintLayout.setOnTouchListener(new OnSwipeTouchListener(getActivity().getBaseContext())
@Override
public void onSwipeLeft()
super.onSwipeLeft();
@Override
public void onSwipeRight()
super.onSwipeRight();
);
【讨论】:
以上是关于Android Studio - 带回栈的导航抽屉的主要内容,如果未能解决你的问题,请参考以下文章
导航抽屉不适合状态栏下方(android studio)[重复]
在 Android Studio 的默认导航抽屉模板中使用按钮在片段之间切换
在 Android Studio 默认模板中更改导航抽屉图标的颜色