Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle touch outside the view in Android?

I've found implementation of "Undo Bar" used in Gmail application for Android. "UndoBar" is basically a View that is displayed on top of the layout.

Unfortunately it's not complete - it has no functionality of dismissing bar by touching screen outside the bar.

I've implemented FrameLayout that overrides onInterceptTouchEvent to handle bar dismissing but touching Action Bar does nothing.

Is there any way to handle such events from Action Bar?

Below there is an Image with "UndoBar"shown. What I want to achieve to handle touch in Action bar represented by red dot.

enter image description here

like image 372
pixel Avatar asked Apr 22 '13 19:04

pixel


People also ask

How do I get touch position on android?

setOnTouchListener(handleTouch); This gives you the touch event coordinates relative to the view that has the touch listener assigned to it. The top left corner of the view is (0, 0) . If you move your finger above the view, then y will be negative.

What is touch slop?

"Touch slop" refers to the distance in pixels a user's touch can wander before the gesture is interpreted as scrolling.

How do you handle touch events in a fragment?

OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if(event. getAction() == MotionEvent. ACTION_MOVE){ //do something } return true; } }); //here the rest of your code return view; MotionEvent.

Which method you should override to control your touch action in Android?

Android supports multiple pointers, e.g. fingers which are interacting with the screen. The base class for touch support is the MotionEvent class which is passed to Views via the onTouchEvent() method. you override the onTouchEvent() method.


3 Answers

Try to override dispatchTouchEvent of your activity.

dispatchTouchEvent(MotionEvent event){

     int x= event.getRawX();
     int y= event.getRawY();


         if(/*check bounds of your view*/){
          // set your views visiblity to gone or what you want. 
         }
      //for prevent consuming the event.
      return super().dispatchTouchEvent(event);    
}

update

dispatchTouchEvent(MotionEvent event){

     int x= event.getRawX();
     int y= event.getRawY();

      return super().dispatchTouchEvent(event)||[YourView].onTouch(event);    
}
like image 59
Ercan Avatar answered Oct 19 '22 19:10

Ercan


To catch touch events for the whole screen including the ActionBar add a view to the Window.

View overlayView = new View(this);
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.TOP;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.token = overlayView.getWindowToken();
overlayView.setOnTouchListener(new OnTouchListener() {
    public boolean onTouch(View view, MotionEvent event) {
        // Get the action bar
        int actionBarHeight = actionBar.getHeight();
        if ((event.getAction() == MotionEvent.ACTION_DOWN)
            && (event.getRawY() < actionBarHeight)) {
            // Touch inside the actionBar so let's consume it
            // Do something
            return true;
        }
        return false;
    }
});
WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mWindowManager.addView(overlayView, p);

Hope this helps.

like image 39
Aswin Rajendiran Avatar answered Oct 19 '22 20:10

Aswin Rajendiran


You should just override Activity's dispatchTouchEvent(ev: MotionEvent) method


Look at this example of dismissing indefinite Snackbar

class MainActivity : AppCompatActivity() {

private var snackbar: Snackbar? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)

    // show indefinite snackbar
    snackbar = Snackbar.make(coordinator_layout, "Hello world!", Snackbar.LENGTH_INDEFINITE).apply {
        show()
    }
}

/**
 * On each touch event:
 * Check is [snackbar] present and displayed
 * and dismiss it if user touched anywhere outside it's bounds
 */
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
    // dismiss shown snackbar if user tapped anywhere outside snackbar
    snackbar?.takeIf { it.isShown }?.run {
        val touchPoint = Point(Math.round(ev.rawX), Math.round(ev.rawY))
        if (!isPointInsideViewBounds(view, touchPoint)) {
            dismiss()
            snackbar = null // set snackbar to null to prevent this block being executed twice
        }
    }

    // call super
    return super.dispatchTouchEvent(ev)
}

/**
 * Defines bounds of displayed view and check is it contains [Point]
 * @param view View to define bounds
 * @param point Point to check inside bounds
 * @return `true` if view bounds contains point, `false` - otherwise
 */
private fun isPointInsideViewBounds(view: View, point: Point): Boolean = Rect().run {
    // get view rectangle
    view.getDrawingRect(this)

    // apply offset
    IntArray(2).also { locationOnScreen ->
        view.getLocationOnScreen(locationOnScreen)
        offset(locationOnScreen[0], locationOnScreen[1])
    }

    // check is rectangle contains point
    contains(point.x, point.y)
}
}        

Or check out the full gist

like image 2
Andrey Busik Avatar answered Oct 19 '22 19:10

Andrey Busik