Search code examples
androidandroid-actionbarhideswipe

Hide the ActionBar when swiping up and show when swiping down


I seem to have an issue with hiding and showing the ActionBar. My app starts with it hidden and I want it to appear back when the users swipes down on any part of the screen and hide it back then the user swipes up.

I have tried implementing this in the following ways:

Method 1: in onCreate

        View mView = getWindow().getDecorView();

        //mView.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_IMMERSIVE;

        mView.setSystemUiVisibility(uiOptions);


        mView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Toast.makeText(context, "Swiped down", Toast.LENGTH_SHORT).show();
                        //getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
                        getSupportActionBar().show();
                        return true;
                    case MotionEvent.ACTION_UP:
                        Toast.makeText(context, "Swiped up", Toast.LENGTH_SHORT).show();
                        //getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
                        getSupportActionBar().hide();
                        return true;
                    default: return false;
                }
                //return false;
            }
        });

Method 2:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        switch (action) {
            case (MotionEvent.ACTION_DOWN):
                Toast.makeText(context, "Swiped down", Toast.LENGTH_SHORT).show();
                getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
                getSupportActionBar().show();
                return true;
            case (MotionEvent.ACTION_UP):
                Toast.makeText(context, "Swiped up", Toast.LENGTH_SHORT).show();
                getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
                getSupportActionBar().hide();
                return true;
            default:
                return super.onTouchEvent(event);
        }  
    }

Now here are the issues:

  1. The function applies only on parts of the screens where I have no buttons or other elements which can be clickable;
  2. Where it applies, it has nothing to do with swipes. It shows the bar as long as I keep the finger pressed on a non-clickable filed in the view.

EDIT:

With the replies from the comment, I managed to make the Action Bar show and hide based on scroll, but I still have the issue with #1, in which I cannot perform the action on any part of the screen.

It works only on the parts where onClickListener is not assessed.


Solution

  • I have managed to solve the issue after a few days of investigation. Seemed that the best choice was to implement a GestureDetector like this

        public class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
    
        private MainGame mainGame;
    
        MyGestureDetector(MainGame mainGame) {
            this.mainGame = mainGame;
        }
    
            @Override
            public boolean onDown(MotionEvent e) {
                Log.d("Gesture", "onDown");
                return super.onDown(e);
            }
    
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                Log.d("Gesture", "onSingleTapConfirmed");
                return true;
            }
    
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                Log.d("Gesture", "onSingleTapUp");
                return true;
            }
    
            @Override
            public void onShowPress(MotionEvent e) {
                Log.d("Gesture", "onShowPress");
            }
    
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.d("Gesture", "onDoubleTap");
                return true;
            }
    
            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                Log.d("Gesture", "onDoubleTapEvent");
                return true;
            }
    
            @Override
            public void onLongPress(MotionEvent e) {
                Log.d("Gesture", "onLongPress");
            }
    
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                Log.d("Gesture", "onScroll");
                if (e1.getY() < e2.getY()) {
                    Log.d("Gesture", "Scroll Down");
                }
                if (e1.getY() > e1.getY()) {
                    Log.d("Gesture", "Scroll Up");
                }
                return true;
            }
    
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                if (e1.getY() < e2.getY()) {
                    Log.d("Gesture", "Swipe Down " + e1.getY() + " - " + e2.getY());
                    mainGame.getSupportActionBar().hide();
                }
                if (e1.getY() > e2.getY()) {
                    Log.d("Gesture", "Swipe Up" + e1.getY() + " - " + e2.getY());
                    mainGame.getSupportActionBar().hide();
                }
                return true;
            }
        }
    

    and implement it in my main activity as an onTouch with listeners for each part of the layout in my main activity. In onCreate:

    layout.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    mViewSelected = v;
                    mGestureDetector.onTouchEvent(event);
                    return false;
                }
            });
    
            gameScoreP1.setOnTouchListener(this);
            gameScoreP2.setOnTouchListener(this);
            fullNameP1.setOnTouchListener(this);
            fullNameP2.setOnTouchListener(this);
    

    and the method to override the gestures:

     @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (myGestureDetector.onSingleTapConfirmed(event)) {
                switch (v.getId()) {
                    case R.id.fullNameP1:
                        diagUtils.changePlayerNameDialog(1, this);
                        return false;
                    case R.id.fullNameP2:
                        diagUtils.changePlayerNameDialog(2, this);
                        return false;
                    case R.id.gameScoreP1:
                        scoreSetter.manageGameSetPoints(1);
                        return false;
                    case R.id.gameScoreP2:
                        scoreSetter.manageGameSetPoints(2);
                        return false;
                    default:
                        return false;
                }
            } else return true;
        }
    

    Issue now is that when I perform the fling movement over a view like gameScoreP1 for example, it also detects the click. Is there any way to make these exclusive?

    EDIT

    Managed to solve the second issue as well by setting the views as clickable like such: fullNameP1.setClickable(true)