1

I have this code

spinner.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (parent.getItemAtPosition(position).equals("Choose an article")){
                }else {
                    String item = parent.getItemAtPosition(position).toString();
                    Toast.makeText(parent.getContext(),"long click: " +item, Toast.LENGTH_SHORT).show();
                }
                return false;
            }
        });

When I debug the code, on long click item event does nothing. The code inside onItemLongClick() is never executed. How can I fix it?

xralf
  • 3,312
  • 45
  • 129
  • 200
  • Do you have any other listeners set to the spinner, such as `OnTouchListener`? – Zain Jul 05 '23 at 20:58
  • I have `spinner.onItemSelectedListener` yet. – xralf Jul 05 '23 at 21:15
  • Your if statement has nothing in it, hence if the program flow enters there you will get nothing printed. Have you tried executing a log statement in `onItemLongClick` directly? – Kozmotronik Jul 07 '23 at 06:06
  • @Kozmotronik The log statement is not executed. The problem is, I'm unable to do a long click, it's only possible to do a short click, or a double click (in emulator and on real device as well). – xralf Jul 07 '23 at 14:58
  • May be this is because the Spinner API is not meant to be used as a long clicking control. I've never tried to use a long click listener with the spinner but it technically can be possible. – Kozmotronik Jul 07 '23 at 15:04

1 Answers1

1

Spinner in Android might not support the setOnItemLongClickListener, due to its UI nature - it is essentially a dialog or dropdown menu. The dropdown menu will close after a short click, so a long click listener is not applicable here, hence why your long click listener is not triggered.

If you want to add additional interaction to the spinner, you could use the normal setOnItemSelectedListener instead.
(Examples here, and "Android - Text is Pushed to the Left in a Spinner")
You would then have to implement your own time logic if you want to simulate a long click event.

But, since the onTouch method is not a part of the OnItemSelectedListener interface, we will need a different approach to simulate a long press on the Spinner. As mentioned, it does not natively support long clicks: one approach would be to create a custom Spinner class where you can manage touch events yourself. A very basic implementation would be:

public class LongClickSpinner extends androidx.appcompat.widget.AppCompatSpinner {

    private static final long LONG_PRESS_TIME = 500; // Time in milliseconds
    private long pressStartTime;

    public LongClickSpinner(Context context) {
        super(context);
    }

    public LongClickSpinner(Context context, int mode) {
        super(context, mode);
    }

    public LongClickSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                pressStartTime = System.currentTimeMillis();
                break;
            case MotionEvent.ACTION_UP:
                long pressDuration = System.currentTimeMillis() - pressStartTime;
                if (pressDuration >= LONG_PRESS_TIME) {
                    // Do your long click action here
                    Toast.makeText(getContext(), "Long click!", Toast.LENGTH_SHORT).show();
                    return true;
                }
                break;
        }
        return super.onTouchEvent(event);
    }
}

You can use this LongClickSpinner in your XML layouts like a normal Spinner. When the user touches the spinner for longer than LONG_PRESS_TIME milliseconds, your "long click" action will execute.

That solution is still a workaround and might not fit all use cases. Spinner is not intended to handle long press events, and its behavior with this custom implementation might not be perfect.


If you need a different interaction paradigm for the selection of items, you might want to consider using another UI component that does support long clicks, such as a ListView or RecyclerView.

With ListView or RecyclerView, you can have a list of items that support both normal clicks (for selection of the item) and long clicks (for showing additional options for example). The long click implementation would then look like this:

listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        String item = parent.getItemAtPosition(position).toString();
        Toast.makeText(parent.getContext(), "long click: " + item, Toast.LENGTH_SHORT).show();
        return true;  // Return true to show that the event has been consumed.
    }
});

The difference between using a ListView or RecyclerView and a Spinner is that the ListView/RecyclerView would always be visible on your layout, while a Spinner would only display its items once it's tapped.

If you want the spinner-like behavior while having the setOnItemLongClickListener functionality, one option would be to create a custom dialog that contains a ListView or RecyclerView. This way, you could emulate the spinner behavior with the benefits of long click listener support.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • This writes an error message (@Override at onTouch method is red underlined). The error says "method does not override or implement a method from a supertype" – xralf Jul 08 '23 at 19:37
  • @xralf True, I have rewritten the first part. But the general idea is: If long press interaction is crucial for your app, you might have to rethink your UI/UX, since Spinner is not intended to handle long press events. – VonC Jul 08 '23 at 19:44
  • I rewritten it a little differently, but it does only long clicks now (even if the LONG_PRESS_DURATION is 2000). I'm using also the short click functionality and your solution is very complicated for me now. – xralf Jul 08 '23 at 19:52
  • @xralf Don't hesitate to post your own implementation you have settled on, after reading this answer. I am curious to know what you have found. – VonC Jul 09 '23 at 17:52
  • I wanted to implement delete functionality for the opened file, but finally I have decided that I will rather use a delete button related to the opened file. first, I thought that one more button will make the app ugly, but it is OK. Your answer is good for explanation that the spinner is not suitable for it. And It was quite complicated for short clicks, because I have to differentiate between user touches and when the spinner runs it's callback automatically when rotating the device screen). Long clicks would make it even more complicated. – xralf Jul 09 '23 at 20:12
  • @xralf Got it, thank you for the feedback. You went with the "rethink your UI/UX" option ;) – VonC Jul 09 '23 at 20:15