First off I am kinda new to Android, so with that being said. So I have a spinner, and every time I make a selection the phone will scroll back up to the last edit text who has focus. That is very annoying so I set the spinner as focusable, but for some reason I then have to click the spinner twice to get it to open (the first click gives the spinner focus, the second opens the spinner). So the best I have come up with so far is this:
activitySpinner = (Spinner) findViewById(R.id.acivity_dropdown);
activitySpinner.setFocusable(true);
activitySpinner.setFocusableInTouchMode(true);
activitySpinner.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
activitySpinner.requestFocus();
activitySpinner.performClick();
return true;
}
});
That takes care of the need for two clicks, but that causes problems because it will open the spinner on the slightest touch, even if all I wanted to do was scroll down. Am I looking at this problem the wrong way? Is there a way to make the spinner focusable and also allow it to open on the first click?
Things I've tried:
Setting focusable in the xml,
setting focusable and focusable in touch mode in java,
the code above
Using setFocusable(true) and setFocusableInTouchMode(true) are correct. To fix the two-touch problem created by the latter check for the ACTION_UP event in your touch handler and return false to let the event bubble up which eliminates the extra requestFocus() call:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !v.hasFocus()) {
v.performClick();
}
return false;
}
The hasFocus() check makes this specific to the click-twice problem; if the control already has focus, your actual tap should bring up the list without additional work.
Try this also
spinner.requestFocusFromTouch();
Related
I am currently working on a Java SDK which gets installed by the original developer in his existing Android app. Now I need to set some event listeners e.g.:
public void registerTouchListener(ScrollView scrollview) {
scrollview.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("SDK", event.toString());
return false;
}
});
}
The issue is that the passed in scrollview might already have a registered listener, so my question is how I can hook into the existing listener or register a second listener?
Maybe too hacky, but could you somehow "Steal" the touch event before it gets to the Scrollview by checking the coordinates of where the touch is going to land and if it's in your list of registered Scrollview. Then act as if you haven't handled the touch event -- that way you could act on that Scrollview prior to it being passed on the touch event?
Rather than providing the API like this, could you rather provide an API that had a function which would call onTouch directly at the end (or beginning) of their event? Not quite as friendly because it won't live in the initialization section, but it will be much clearer and less buggy.
I have a dialog child view of a ViewPager that I have a setOnKeyListener() and setOnClickListener() setup. However, even when the child view is in visible focus (it's a dialog over the ViewPager) on the app, the listener never gets called on a key press. Further investigation seems to show that a ViewPager won't pass on the dispatchKeyEvent() if it has focus. However, if I set an OnKeyListener on the ViewPager with the code:
mViewPager.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP
&& event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
final int childIndex = mViewPager.getCurrentItem();
mViewPager.getChildAt(childIndex).performClick();
}
return false;
}
});
The explicit click call on the child will activate the OnClickListener. However, I really shouldn't have to do that. The event should be passed down the view hierarchy. Is this the generally accepted way to deal with this? Having to explicitly call the child like this feels wrong.
Apparently this is intended behavior. In order for children to receive events, the ViewPager needs code to explicitly handle it. Part of this seems to be due to how even if a large list of views is given to the PageViewer, only a subset is usually actively cached and can have methods called on it. If I want all children to react to, let's say, a click, I would need to do something like:
for(int i=0; i<mViewPager.getChildCount(); i++){
mViewPager.getChildAt(i).performClick();
}
If your child Views have a OnClickListener set, then it will react to the clicks but only if that view is currently in the active ViewPager cache. If your Views has some kind of state that can be changed based on actions (like a new drawable appears on click and disappears with another click) then the only way to make all View children affected that I found seems to be that you need to have a controller that keeps track of the state and sets an OnPageChangeListener that iterates through the "active" children Views and ensures they are all in the proper state.
i have a game, consisting of 7 buttons , arranged such that 1 button is in the center and rest 6 around it.
click on the buttons results in change in textview. using click can really be cumbersome for the user, therefore i would like to add functionality of dragging finger over buttons to perform onclick ..something similar to boggle type of games like -> https://market.android.com/details?id=com.ant.wordfind.client&feature=search_result
i have tried to implement the same ,problem is when i drag of finger only one button gets registered , even if i press other buttons by dragging cursor -> other button touch are just ignored.given the
following code.
public boolean onTouch(View v, MotionEvent arg1)
{
if(arg1.getAction() ==MotionEvent.ACTION_MOVE)
{
Button b;
switch (v.getId())
{
case R.id.b1:
case R.id.b2:
case R.id.b3:
case R.id.b4:
case R.id.b5:
case R.id.b6:
case R.id.b7:
b = (Button)findViewById(v.getId());
b.performClick();
break;
}
return true;
}
am i missing somethng ? wht i want is whn buttons are touched ..they perform onclick functionality.once one button click is registered rest touches are ignored
any help would be appreciated .
i dont want something like piano/soundboard where there is continuous click of button ..but just one click as i drag finger over the button
thanks !
At onTouch(), you shouldn't always use return true. Return false if you want the subsequent actions to be captured.
onTouch() - This returns a boolean to indicate whether your listener consumes this event. The important thing is that this event can have multiple actions that follow each other. So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event.
Ref: http://developer.android.com/guide/topics/ui/ui-events.html
I have a few buttons in a tab layout for which the OnClickListener works fine. The purpose of these buttons is to start a new activity when clicked upon. I want my code to work for the touch mode of the phone as well. In other words I wanted to know how to implement the OnTouchListener for the code. Currently I have something like
public boolean onTouch(View v, MotionEvent event) {
startActivity(new Intent().setClass(this, OtherActivity.class));
return true;
}
I am just thinking about it the same way as I would think about the onClick() method but apparently I am wrong.
Any help in this matter would be appreciated.
Thanks!
Touching a button on the screen should generate click events the same as using a hardware keypad. Try using the Log object and LogCat to see when methods are called.
What I want to do is change the default "Done" label that appears in the virtual keyboard. Here's what I've tried without any luck:
mSearchInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
mSearchInput.setImeActionLabel(getString(R.string.search_action_label), EditorInfo.IME_ACTION_DONE);
I am able, however, to handle a click on that button, with this:
mSearchInput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
performSearch();
return true;
}
return false;
}
});
I'm clueless as to how I can change the label on that button at the moment.
The imeActionLabel sets the label for the button that appears on the top right on full screen IME mode (i.e., when your phone is in landscape). If you want to change the button to the bottom right of the keyboard, you can pass certain flags to imeOptions.
As far as I know, for that button you're limited to a certain set of actions (see here for a full list of supported flags), but since you seem to want a search button, all you have to do is to slightly adjust your first line and use IME_ACTION_SEARCH:
mSearchInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
Mind you, the exact appearance of that button will depend on the input method. The default Android keyboard shows a magnifier for the search flag, while the Touch Input (HTC's keyboard) seems completely unaware of that flag, still showing a return button.