Quick, probably simple, question. I have a view whose background is animating, and during that time, I want to disable the user from interacting with the view. My view is a FrameLayout, and I'm capturing touch events with onTouchEvent(). Solutions I've tried:
1) First setOnTouchListener(null), then setOnTouchListener(this). Problem is, my view only calls onTouchEvent(MotionEvent), and not onTouch(View, MotionEvent), so I can't pump through the Events there.
2) First setEnabled(false), then setEnabled(true). The source code says: A disabled view that is clickable still consumes the touch events, it just doesn't respond to them. Problem is, MotionEvents still get pumped through in onTouchEvent().
3) requestDisallowInterceptTouchEvent(false), then (true). This only handles touch events from the parent.
The solution I have working is using a boolean variable isAnimating, and checking the value of that in onTouchEvent(). I'd rather not do this, because it looks ugly to me and I'd rather use the API for it than reinvent the wheel, sooo... anyone got any ideas? Thanks.
Try:
setFocusable() and setFocusableInTouchMode()
Try:
#Override
public boolean onTouchEvent(MotionEvent event) {
//Check if event is on your view
if(event.getY()>view.getTop()&&event.getY()<view.getBottom()&&event.getX()>view.getLeft()&&event.getX()<view.getRight()){
//event occured inside your view
}
//here return super or as your logic prefer
return super.onTouchEvent(event);
}
Related
I'm working on improving the accessibility within my app.
I have pretty complicated layout with cards. Each card has some clickable objects inside it, but it also has the global click-listener.
When I enable Talkback, select the card (not something inside it!), double-clicking (to open the card), the card gets the touch-event in the middle of the card.
As a result, nested object got click event and react respectively.
The question is how to determine, which item is in TalkBack's focus (green-rectangle-thing for me)? The idea is to disable inside touch-listeners, if card itself is in focus.
API level I want to support is 16 (Android 4.1+)
Thanks!
I think what would work best for you, is to override the accessibility delegate of layout view, listening for accessibility focus events. When focus is added to a card, remove listeners, when focus leaves your cards re attach your listeners. Attach this delegate to your layout view, and you should be able to watch as various views within your layout obtain and give up accessibility focus.
class MyAccessibilityDelegate extends View.AccessibilityDelegate {
#Override
public boolean onRequestSendAccessibilityEvent(ViewGroup viewGroup, View child, AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
//Do stuff in here! Maybe also do different stuff when focus is cleared!
}
return super.onRequestSendAccessibilityEvent(viewGroup, child, event);
}
}
The apis for this were added in API level 14 so you should be good to go!
I am developing an android app which tracks touch events for the whole application. For that purpose, I want to override onTouchEvent() without an activity; i.e., inside a simple Java class, I don't whether it's possible. Any ideas are welcome.
No, you cannot arbitrarily override onTouchEvent, particularly in a "simple Java class", i.e. one that does not extend a View.
Solution 1
If you want to capture all touches to your app, override onInterceptTouchEvent() in your main layout. So, if your main layout is a LinearLayout, do something like:
public class MyTouchLayout extends LinearLayout {
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Do whatever with your touch event
return false; // Do not prevent the rest of the layout from being touched
}
}
Then, in your XML, you'd use:
<com.example.MyTouchLayout
...
>
<!-- The rest of your layout -->
</com.example.MyTouchLayout>
Solution 2
This is by far the simpler solution, though I've had varying luck with it in the past and would never suggest that you reply upon it.
You can simply get the View that contains all your content (the root View, a LinearLayout above), then give it a listener.
View v = findViewById(android.R.id.content); // Find the root View; you may have to give it your own ID in the XML, and use that
v.setOnTouchListener(new OnTouchListener {
// ...
}
I would like to process all touch events at the container level. In other words, I want all touch events to reach the container level. Right now I am finding that TouchEvents only reach the containing ViewGroup if the location of the touch does not land on a UI Component that is contained by the view group. The contained UI Element processes the TouchEvent and it does not bubble up to the container. Does anyone know how to guarantee that all touch events reach the top level container?
Just to be clear, picture an activity with several buttons, several edit texts, and several check boxes. A typical form. Normally I am seeing that each UI component will catch the TouchEvent that lands on it and the container is none the wiser. So I want to know how the container/viewgroup could be informed of all touches that land anywhere within its region whether or not that region is occupied with a button, empty space or an edit text.
This is how I interpret your question:
You have View tree like this
ViewGroup G
View A
View B
...
and you want G to handle the MotionEvent created on touch even if it was consumed by any of A, B, ...
How to:
I'll give you two options. Depending on if you want to ignore consumption by
every child
only selected children
use one of the following templates:
Override dispatchTouchEvent() in G
// In G
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
super.dispatchTouchEvent(event);
// Handle event here instead of using an OnTouchListener
return true;
}
Override dispatchTouchEvent() in every child whose consumption should be ignored
Ignore some children
// In every child whose consumption should be ignored
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
super.dispatchTouchEvent(ev);
return false; // false means "I did not consume the event"
}
Don't forget to setup your listener
// In G, before touch should be recognized
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Handle event here
return true; // true means "I did consume the event"
}
});
Measured in lines of code, option 1 is a lot simpler. Option 2 is there just in case you need special treatment for some of A, B ...
I know it is late, but I think future readers might want to look at ViewGroups.onInterceptTouchEvent().
In order to have list reordering functionality I turned to this implementation.
My problem is that when I try to drag an item in my ListView, I don't get the ACTION_DOWN event. Instead, for a single smear down motion I get 2 ACTION_MOVE events (action=0x00000002) and a single ACTION_UP event (action=0x00000001) in this order.
I've looked at similar questions but it seems like everyone has the opposite problem, getting only ACTION_DOWN events.
Can anyone think of why this is happening?
Thanks,
Yoel
I was using the same code.
My problem was also that something was consuming the event and I didn't managed to found what was it... but i managed to solve it using onInterceptTouchEvent to return true on the events i needed on onTouchEvent.
Problem solved :-)
It turns out I needed to add this small piece of code:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
Now I get the ACTION_DOWN events in the OnTouchEvent function and it all works fine.
New to programming, now to android. So I hope I dont annoy you to much.
How would I go about setting an onkeylistener at the top level of the app that captured the keyevent no matter what.
Basically what i have is a linear layout with dynamically added edittexts.
I want to capture the Enter key event and have it get the current edittext, perform some tests then create a new edittext and add it to the layout.
I know I can (and have) implement an onkeylistener to individual child views, but not being a programmer, the logic seems weird to create an edittext that listens for input to create another edittext that listens for input to create another.... (you see where this goes)
Can anyone point me in the right direction?
I have lots more info about what Im trying to do, I just dont know what is pertinent and what is not, so let me know if you need more.
Thanks for your time in advance,
Chris
Take a look at http://developer.android.com/reference/android/app/Activity.html#dispatchKeyEvent%28android.view.KeyEvent%29
What you want is to intercept all the events before they are processed by any View in the window. Return true if the event was handled or false if you want the childs to process the event further.
Like Ben said your activity can implement OnKeyListener then for each EditText you create, set the OnKeyListener to be the activity.
editText1.setOnKeyListener(this);
And then in your implementation of onKey you can handle the key press event.
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(v == editText1) {
// do something
} else if( v == editText2 ) {
// do something
}
return true; // return true if you handled the keypress
}
Your activity can implement OnKeyListener.