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 的默认导航抽屉模板中使用按钮在片段之间切换

在 Android Studio 默认模板中更改导航抽屉图标的颜色

Android Studio 导航抽屉,如 Gmail 应用

Android Studio 中导航抽屉预览中的渲染问题