onTouchEvent() will not be triggered if setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) is invoked

后端 未结 8 664
有刺的猬
有刺的猬 2021-02-01 16:11

I call

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) 

when my app starts to make my app able to displa

相关标签:
8条回答
  • 2021-02-01 16:19

    Android 4.4 (API Level 19) introduces a new SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility() that lets your app go truly "full screen." This flag, when combined with the SYSTEM_UI_FLAG_HIDE_NAVIGATION and SYSTEM_UI_FLAG_FULLSCREEN flags, hides the navigation and status bars and lets your app capture all touch events on the screen.

    0 讨论(0)
  • 2021-02-01 16:19

    What I've done is first imported android.view.GestureDetector so I can use it to detect gestures. Android has a number of default gestures that are automatically detected in the GestureDector class. Most of this info is found here, but below is code in a form that I've used in an actual project that works.

    First I've made an anonymous class in my Activity (this can be nested wherever, but I tend to make my anonymous classes at the bottom, right before the closing bracket). NOTE: You can also implement OnGestureListener as part of your class, also.

    The code below is for using gesture detection to give a simple hide/show.

    I've declared and defined my action bar (my UI, which is initially hidden) as an instance variable, so I can access it here, and wherever else, but you can substitute it for a getActionBar().show() and getActionBar().hide() in the case you don't want to declare it as an instance variable. Substitute your UI in the place of the actionBar here:

    public class Example extends ActionBarActivity {
    
        // declared in onCreate() method
        private android.support.v7.app.ActionBar actionBar; 
        private GestureDetectorCompat mDetector;
        private YourView view1;
        private YourView view2;
        private YourView view3;
        private YourView view4;
    
        // some other code
    
        class GestureListener extends GestureDetector.SimpleOnGestureListener {
    
        private static final String DEBUG_TAG = "Gestures in Example Class";
    
            @Override
            public boolean onDoubleTap(MotionEvent event) {
    
                Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
                // if there is a double tap, show the action bar
                actionBar.show();
    
                return true;
           }
    
           @Override
           public boolean onSingleTapConfirmed(MotionEvent event) {
    
                Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
    
                // if the tap is below the action bar, hide the action bar
                if (event.getRawY() > getResources().getDimension(R.dimen.abc_action_bar_default_height)) {
                    actionBar.hide();
                    return true;
                }
    
                return false;
            }
    
            @Override
            public boolean onDown(MotionEvent event) {
    
                 return true;
    
            }
    
    } // end-of-Example Class
    

    Then in my onCreate() I've declared my GestureDetector and also (optionally) set my GestureListeners:

    private GestureDetectorCompat mDetector;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // some code here
        mDetector = new GestureDetectorCompat(this, new GestureListener());
    
        // this code is for more advanced view logic not needed for a basic set-up
        //setGestureListeners();
    
    } // end-of-method onCreate()
    

    Then in order to actually send gestures to be processed we provide the instructions for doing that, there are two ways I know about, first the simplest:

    /**
    * This method recognizes a touchEvent and passes it to your custom GestureListener 
    * class.
    */
    @Override 
    public boolean onTouchEvent(MotionEvent event){
    
         this.mDetector.onTouchEvent(event);
    
         return super.onTouchEvent(event);
    }
    

    The second way is more complex, but if you want to only recognize touch events on certain Views in your layout as in the case where you have overlapping views and can only access the top View, you can create a custom class to pass the event around or up:

    class MyOnTouchListener implements View.OnTouchListener {
    
        public boolean onTouch(View v, MotionEvent event) {
    
            if (v.equals(view4)) {
                return mDetector.onTouchEvent(event);   
            } else return false;
        }
    } // end-of-class MyOnTouchListener
    

    and then use it here:

    public void setGestureListeners() {
    
        /* when we return false for any of these onTouch methods
        * it means that the the touchEvent is passed onto the next View.
        * The order in which touchEvents are sent to are in the order they
        * are declared.
        */
        view1.setOnTouchListener(new MyOnTouchListener());
    
        view2.setOnTouchListener(new MyOnTouchListener());
    
        view3.setOnTouchListener(new MyOnTouchListener());
    
        view4.setOnTouchListener(new MyOnTouchListener());
    
    
    } // end-of-method setGestureListeners()
    

    In my setGestureListeners method, I gave them all the same set of commands, that essentially only recognizes touchEvents on view4. Otherwise, it just passes the touchEvent to the next view.

    This is code using AppCompat, but if you are not building for older versions, you can use the regular GestureDetector and ActionBar.

    0 讨论(0)
  • 2021-02-01 16:21

    Have you tried adding code to only show your UI when the state has changed? You have to maintain the last known visibility and only show your UI when you first come into being visible:

    int mLastSystemUiVis;
    
    @Override 
    public void onSystemUiVisibilityChange(int visibility) {
        int diff = mLastSystemUiVis ^ visibility;
        mLastSystemUiVis = visibility;
        if ((diff&SYSTEM_UI_FLAG_VISIBLE) != 0
                && (visibility&SYSTEM_UI_FLAG_VISIBLE) == 0) {
            // DISPLAY YOUR UI
        }
    }
    

    Code sample adopted from the Android docs

    0 讨论(0)
  • 2021-02-01 16:24

    The method Activity.onTouchEvent() gets called at the end of the responder chain (meaning after all other views have had a chance to consume the event). If you tap on a view that is interested in touch (i.e. a Button or EditText) there's a good chance your Activity will never see that event.

    If you want to have access to touches before they every get dispatched to your view(s), override Activity.dispatchTouchEvent() instead, which is the method called at the beginning of the event chain:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        //Check the event and do magic here, such as...
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
    
        }
    
        //Be careful not to override the return unless necessary
        return super.dispatchTouchEvent(event);
    }
    

    Beware not to override the return value of this method unless you purposefully want to steal touches from the rest of the views, an unnecessary return true; in this spot will break other touch handling.

    0 讨论(0)
  • 2021-02-01 16:30

    I had a very similar issue with trying to update the UI from an onTouchEvent() requiring two touches to work, and I tried a bunch of elaborate stuff before finally getting it to work on the first click.

    In my case, I was showing a previously hidden item, then getting its height, then moving a button down by that height. The problem I ran into is that the height was showing as 0 until after the first touch event finished. I was able to solve this by calling show() during ACTION_UP for the onTouchEvent() instead of its ACTION_DOWN. Maybe it'd work if you did something similar?

    0 讨论(0)
  • 2021-02-01 16:32

    This did work for me:

     setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
                    // show my app UI
                }
            }
        });
    
    0 讨论(0)
提交回复
热议问题