最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Show top items when clicking on a spinner without changing the selection - Stack Overflow

programmeradmin3浏览0评论

In my Android app, I have a spinner many items (enough to not be able to display all of them at the same time. Scrolling is needed) The default behavior of the spinner is that when you click on the spinner, the previously selected item is display at the top of the dropdown. The users complain that it is confusing to not always have the same display of the list when opening the spinner.

So I would like to change the behavior like this: when the spinner is clicked:

  • the dropdown always shows the first item of the list
  • the previously selected item is still selected (it may even not be displayed)

I did not find any way to change the display of the dropdown without changing the selection

How can I do that?

In my Android app, I have a spinner many items (enough to not be able to display all of them at the same time. Scrolling is needed) The default behavior of the spinner is that when you click on the spinner, the previously selected item is display at the top of the dropdown. The users complain that it is confusing to not always have the same display of the list when opening the spinner.

So I would like to change the behavior like this: when the spinner is clicked:

  • the dropdown always shows the first item of the list
  • the previously selected item is still selected (it may even not be displayed)

I did not find any way to change the display of the dropdown without changing the selection

How can I do that?

Share Improve this question asked Jan 20 at 7:44 Laurent D.Laurent D. 4801 gold badge7 silver badges25 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

after scratching my head around the original source files of Spinner class and other related classes, i couldnt find any attribute that needs to be changed, neither had any luck with overriding the classes nor with using an custom implementation,

so finally i came up with a workaround

  • define a global variable flag
boolean flag=true;
  • basically you need to create another spinner and position it exactly with the original or the first spinner, also with the same height and width
<Spinner
        android:id="@+id/duplicatespinner"
        android:visibility="invisible" />
  • disable the duplicate spinner, to prevent unexpected bugs and outcomes
Spinner duplicateSpinner = findViewById(R.id.duplicatespinner);
duplicateSpinner.setEnabled(false);
  • then assign the same adapter ( the one set to the original spinner ) to the new spinner (duplicate spinner)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_spinner_item, items); // replace items with your arrayList
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

originalSpinner.setAdapter(adapter);

duplicateSpinner.setAdapter(adapter);
  • add a OnTouchListener to the original spinner, and stimulate click action on the duplicate spinner, and prevent the default behaviour of the original spinner
originalSpinner.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        duplicateSpinner.performClick(); // stimulates the click action to the duplicate spinner
        return true; // prevents the default behaviour on touch, basically stops the other methods from handling the touch event ( similar to stopProgataion in JavaScript )
    }
});
  • add a OnItemSelectedListener to the duplicate spinner, which selects the same item present on the original spinner, also reset's the duplicate spinner selection to zero or top element
duplicateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if(flag) {
            originalSpinner.setSelection(position);

            flag = false;
            duplicateSpinner.setSelection(0);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(26);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    flag = true;
                }
            }).start();
        }
    }
    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});

so what the above code does is as soon as you select an item from the dropdown of the duplicate spinner ( visually the dropdown looks exactly as the dropdown of the original spinner ), this code makes sure that the same item is selected in the original spinner ( originalSpinner.setSelection(position); ) , meaning that the visual appearance and working of the the original spinner has not been changed, and is the same as it should be

now to make sure the dropdown is from the beginning or the top, we set the selection of the duplicate spinner to zero, meaning the dropdown now will be shown from the top, but when the duplicateSpinner.setSelection(0); statement is executed, immediately the OnItemSelectedListener is called , which made the original spinner's item selected to zero ( which is not desired ), to prevent this i introduced a variable called flag, which would prevent the call of OnItemSelectedListener after using duplicateSpinner.setSelection(0);,added a delay of 26ms as without the delay the flag was being set to true, before duplicateSpinner.setSelection(0); was executed and called the OnItemSelectedListener, which was not desired,

the delay of 26ms was the minimum i could go, while preserving the expected output, make changes accordingly, the time could vary based upon the operations needed to perform, the ui changes made, also the memory available on the running device ( set a delay value that is universal so that it would not cause any unexpected bugs )

you could use an other method to create a delay, i feel comfortable while creating a delay like this, but this can cause a memory overhead

in brief, we are using two spinners one which performs the required actions ( and it does not interact with the user ) and one which is just interacts with the user and tells the other spinner how to act accordingly

i hope this helps you out, also i hope u have understood how this works, if anything that seems unexplained by me, feel free to ask

also dont forget to change the way how delay has been achieved, and also change the delay time accordingly

发布评论

评论列表(0)

  1. 暂无评论