On Android, is there a way to disable Spinner behavior for long press?

The default behavior of a spinner is that when it is “closed”, clicking on it will “open” it and show you a drop-down list. I believe this behavior is potentially very problematic for the user. For example, if they try to scroll something on the screen and happen to “capture” a place that has a counter, then instead of scrolling, it will open a drop-down list in a second or so, and the user will basically leave a finger on one of the drop-down options ( which they can now accidentally click).

So, I would like to disable this behavior with a long press and open the “direct” spinner only when he clicked, not a long press. Is it possible?

+8
android spinner long-press
source share
4 answers

So, I figured out a relatively simple way to do this, although it's not very elegant. Basically, I created a transparent overlay view on top of Spinner and determined that it has an OnClickListener that just triggers a Spinner click.

XML:

<Spinner android:id="@+id/spinner" android:layout_width="match_parent" android:layout_height="40dip" /> <View android:id="@+id/spinner_overlay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/spinner" android:layout_alignRight="@id/spinner" android:layout_alignTop="@id/spinner" android:layout_alignBottom="@id/spinner" /> 

Java:

  View spinnerOverlay = findViewById(R.id.spinner_overlay); spinnerOverlay.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { spinner.performClick(); } }); 
+2
source share

If you need to restore standard click behavior, this is a simpler and more compact version. Jordi's answer :

 spinner.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { v.performClick(); } return true; } }); 

Further thoughts

This behavior also annoyed me. After the investigation, it seems that he has a name: drag to open. You can see how it is defined in the source of the AppCompatSpinner#onTouchEvent() method.

Some problems that I see with this forced behavior (and the reason some people want to disable it):

  • It allows the user to select disabled values ​​in the counter. With a long press, drag and drop, you can select values ​​that cannot even be selected during normal interaction (click to open + click to select)
  • As a consequence of # 1, it can also make the Espresso test very easy. Indeed, in espresso the duration of the click is rather unstable, and one tap can quickly turn into a long press and the choice of interaction.
  • Finally, the biggest problem here is that there is no method / XML attribute to disable drag and drop behavior ...

Let it be fixed!

I opened a ticket related to this in the AOSP issue tester: # 228953 . Feel free to follow him or comment if I missed something.

+3
source share

Have you tried Android: longClickable = "false" in xml yet?

or try something like this:

 spinner.setOnTouchListener(new View.OnTouchListener() { private static final int MAX_CLICK_DISTANCE = 15; private static final int MAX_CLICK_DURATION = 1000; private long pressStartTime; private float pressedX; private float pressedY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { pressStartTime = System.currentTimeMillis(); pressedX = event.getX(); pressedY = event.getY(); break; } case MotionEvent.ACTION_UP: { long pressDuration = System.currentTimeMillis() - pressStartTime; if (pressDuration < MAX_CLICK_DURATION && distance(pressedX, pressedY, event.getX(), event.getY()) < MAX_CLICK_DISTANCE) { //when long clicked. } break; } } return false; } 
0
source share

A bit late, but perhaps still useful for someone:

Setting OnLongClickListener , which returns true in onLongClick , prevents Spinner opening (inadvertently) because it works as if the callback consumed a long click, as indicated in.

 spinner.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { return true; } }); 

The only downside is that the spinner will still have an onTouch animation with a long press.

0
source share

All Articles