I've a Spinner and its content depends on actual location (GPS position). So the content should changes continually, but it's only visible to the user when he/she selects an item. Instead of having a thread who continually updates the Spinner content, or a button to force an update from the user, I'd like to obtain another behaviour.
When the user touches the Spinner, before the Spinner opens, it should be updated. I'm already able to change programmatically the Spinner's content. What I need is an event that triggers when the user touch the closed Spinner, but before the opened Spinner is shown.
I hope this question is clear enough. Thank you for you attention.
You can use onTouchListener
spinner.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
// Load your spinner here
}
return false;
}
});
Related
I have a TextView that has the isSelectable attribute set to TRUE but i also have a onClickListener on it because. I want if a person holds on the text the text to be selected and he can copy it but if he just clicks on it i want a screen to be opened.
this.subtitle.setTextIsSelectable(true);
this.subtitle.setOnClickListener(v -> openMyScreen());
So what happens is that the selection works fine but if you click on it, the first event is consumed somewhere and only when i click for the second time it works. Does any 1 have any idea how i can fix this.
So the issue is, when you click it once, the textview gets focused. That's what's consuming your click event. The only work around I have been able to find is using setOnFocusChangeListener on the textview, then check if the texview got focused, and use that as a click event.
textview.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// Handle click event
}
}
});
Please note that you will still have to use OnClickListener as well to handle click events post focusing
I have a customized GridView populated by a customized BaseAdapter. The selection mode of the GridView is MultiChoiceModal. I want to control which items can be activated when long clicked while still ensuring they respond to (short) click events. BaseAdapter has a method called isEnabled, the perfect solution would be if it had a method isActivatable that behaved analogously. The next best solution would be to intercept long clicks and pass them along to the default handler only when acceptable.
Here are some things that don't work:
Overriding isEnabled in the adapter. This is overkill. In that case, the items cease responding to click events.
Calling setLongClickable for the parent view of each item in the adapter's getView method. This is fraught with problems even if it worked. Needless to say it doesn't. Likely a byproduct of the selection mode.
Setting a custom onLongClickListener for the parent view of each item in the adapter's getView method. Android Studio suggests against this when using any AdapterView. It suggests overriding onItemLongClick instead.
Overriding onItemLongClick in the GridView. Evidently, that is also handled for you when in this selection mode.
Setting a custom onItemLongClickListener in the GridView.
While the hive works on this, I am going to try aborting the action mode's creation/blocking activation of prohibited items in the onItemCheckedStateChanged method of my AbsListView.MultiChoiceModeListener. Clearly I'm running low on ideas.
I have found a simple solution:
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
or
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
where view is the item where you want to prevent a choice mode activation after a long click.
Is there a clever way to "do something" every time a user clicks or taps on the screen? I'd like to know which view they tapped on, and do it without having to replace all my standard views with custom views.
Basically, I want to add click tracking in my app to help with analytics. We already have page tracking (by using a shared superclass for every activity), but in some cases page tracking isn't enough and we actually want to track clicks.
How can I execute a function every time the user clicks on a View on the screen?
In each of your Activities, just add this at the end of onCreate (this is especially easy if all your Activities are subclasses of a custom Activity, because then you only need to write this once):
getWindow().getDecorView().findViewById(android.R.id.content).setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent e) {
//handle your code here
return false;//don't absorb the touch.
}
});
Edit
The above code does not allow easy recognition of which Views are touched. The below code will. Note that this may break other onTouchListeners if the View in question already has registered an onTouch event. If not, this will work great. It uses the droidQuery library to select all views in the hierarchy and set uses code like above to handle touches without absorbing the event. The best place for this would be at the end of onCreate, in every Activity:
First, select the highest level of the architecture you want. If your layout's root view has an id, that would be the best thing:
$.with(this, R.id.root_id)
If not, either add one, or select the topmost view (above your layout). Note that for analytics this may provide some results you do not need:
$.with(this).selectAll()
Now, on the end of this selection, append the following:
.each(new Function() {
#Override
public void invoke($ d, Object... args) {
d.view(0).setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent e) {
//do something with the clicked view, such as:
handleTouch(v, e);
return false;//don't absorb the touch.
}
})
}
});
Then have a new method:
private void handleTouch(View v, MotionEvent e) {
//handle the view touch.
}
I'm trying to implement a custom keyboard in Android. I want to input some text in my Webview. Since I don't want to display the keyboard when I hit everywhere in the Webview I was thinking of a listener of something like this:
webview.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if (((WebView) v).getHitTestResult().getType() == EDIT_TEXT_TYPE)
showMyKeyboardHere();
return false;
}
});
is my listener, it seems to return EDIT_TEXT_TYPE on the key press I do AFTER I've pressed the edit text field. So when I press the edit text field it returns UNKNOWN_TYPE and the click after that when pressed somewhere else returns EDIT_TEXT_TYPE. My guess would be that the OnTouchListener happens before the touch even gets sent on to the Webview it won't have registered it. Any way to change that?
Now to my question: Since I will only want my custom keyboard in this application, is there anyway to listen to whatever event is called to bring up the normal keyboard and immediately hide it and show my own?
What I want to achieve:
A list item is highlighted when the user is pressing it
When the user stops pressing it, the list item:
remains highlighted, if it was unselected before the pressing
loses the highlight, if it was selected before the pressing
Long clicks behave the same way as the user stopping the pressing (changing the background of the item depending on its previous state)
Scrolling the list, without pressing any specific item, should not highlight any item
Details:
For what I read, I think that behaviour could be achieved using list selectors and the state android:state_activated, but this state was introduced in API level 11. The solution I am looking for has to work in API level 10
I think that solutions relying on click (onItemClick, onClick...) will not work, because the click is triggered after the user stops the pressing, not when he starts it (like the pressed state does). Changing the highlight of an item using android:state_pressed is not persistent (it will change back after the press is finished) and changing it in android:state_pressed and making it persistent on click will produce a flicker
A good example of app that achieves that in API level 10 is Tasks. Just click or long click on items in the list to see the desired behaviour
So, anybody has already solved that? Any idea on how the Tasks app does it?
You probably want to set a OnTouchListener(in the getView method) on the row View. That way you'll see the MotionEvent for the first touch(the MotionEvent.ACTION_DOWN action) and can set the selection:
private OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setBackgroundColor(Color.RED); // set the selection
}
// don't forget to store this new status so the adapter will see
// it. Otherwise you'll have some problems when the list will be
// scrolled.
return false;
}
};
I finally solved that issue implementing my own list (PressListView) extending ListView. PressListView has a callback to notify the user when an item on the list has been pressed.
Knowing when the items are pressed (which was the most difficult part), the only thing left is handling in a proper way the backgrounds of the item, which you can do in your own Adapter using selectors.
For those interested on seeing this fully working, take a look at my demo project.
You can launch the CAB performing a long click in an item, and once in CAB you can test the highlighting of items, both with touches and D-pad/trackpad.
Although my solution works as I wanted, it is still slower than the list in the Tasks app, when changing the state of the items. If you try to select two items really fast, most of the times it will not select one of the items on my example, but it will in Tasks. If someone knows what it can be, I would be extremely grateful!
Implement ActionMode on your ListView (see second link below). In ActionMode, the ListView keeps track of the item checked state automatically when the user clicks on an item. When you are using an adapter for your ListView, you set the background of an item based on the checked state:
#Override
public void bindView(final View view, final Context context, final Cursor cursor)
{
int pos = cursor.getPosition();
boolean selected = ((SessionsActivity)context).listView.isItemChecked(pos);
if(!selected)
view.setBackgroundResource(R.drawable.list_selector);
else
view.setBackgroundResource(R.drawable.list_selector_active);
...
AND, you also need to invalidate the ListView, after each item click:
private AbsListView.MultiChoiceModeListener multiChoiceModeListener = new AbsListView.MultiChoiceModeListener()
{
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked)
{
// Here you can do something when items are selected/de-selected,
// such as update the title in the CAB
listView.invalidateViews();
}
See https://stackoverflow.com/a/50639298/2477937 and https://medium.com/over-engineering/using-androids-actionmode-e903181f2ee3