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.
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.
"Touch slop" refers to the distance in pixels a user's touch can wander before the gesture is interpreted as scrolling.
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.
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.
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);
}
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With