Setting spinner text color programmatically lags,

2019-07-11 07:35发布

问题:

TLDR: My spinner displays the wrong color for a split second.

I have a problem with my spinner. Whenever I run the app, if the activity is not cached in memory, it sometimes lags. The text is a default color (like black) before I can set it to the right color. It looks really unprofessional.

Video: Please watch this screen recording to see this in action: https://drive.google.com/file/d/0By2AG5yaBEhMRnRsbVBDU251STQ/view

How it looks for one split-second while loading the page:

How it looks after the lag time (and how it is supposed to look from the start):

Code:

public class MyActivity extends AppCompatActivity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        Spinner spinner = (Spinner) findViewById(R.id.spinner);

        //Get rid of the normal toolbar's title, because the spinner is replacing the title.
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        //Set the choices on the spinner by setting the adapter.
        spinner.setAdapter(new SpinnerAdapter(toolbar.getContext(), new String[]{"Overview", "Story", "Specifications", "Poll", "Video"}, accentColor, backgroundColor));

        //Set the listener for when each option is clicked.
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
        {

            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
            {
                //Change the selected item's text color
                ((TextView) view).setTextColor(backgroundColor);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent)
            {
            }
        });
    }
}

XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
                                   xmlns:app="http://schemas.android.com/apk/res-auto"
                                   android:layout_width="match_parent"
                                   android:layout_height="wrap_content"
                                   android:background="@color/ColorPrimary"
                                   android:elevation="4dp">
    <Spinner
        android:id="@+id/spinner"
        app:popupTheme="@style/AppTheme.PopupOverlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</android.support.v7.widget.Toolbar>

回答1:

What I was doing wrong:

Before, I was following the advice of this answer, and setting the text color in the onItemSelected method, but that method is only called automatically after the UI is done, and you cannot call onItemSelected directly from your code. That was causing a lag. (But it is still needed for when you choose an item from the drop down list - see my solution to this question.)

Solution:

The strategy is to obtain the "Selected" view and set its text color before onCreate finishes. When I tested it in the debugger, no UI is shown during the onCreate method, so this is guaranteed to work.

I just had to add this code after the call to setAdapter(...):

//Set the text color of the Spinner's selected view (not a drop down list view)
spinner.setSelection(0, true);
View v = spinner.getSelectedView();
((TextView)v).setTextColor(backgroundColor);

The key point is to call spinner.setSelection(0, true) with the true parameter. Otherwise, if you just call spinner.setSelection(0), the View v would be null. I found out about this thanks to this answer.

Complete method:

Here is the complete method. NOTE: The code in onItemSelected still needs to be there! Because otherwise, every time you select an item from the drop down list, it will have the wrong color.

@Override 
protected void onCreate(Bundle savedInstanceState)
{ 
    Spinner spinner = (Spinner) findViewById(R.id.spinner);

    //Get rid of the normal toolbar's title, because the spinner is replacing the title. 
    getSupportActionBar().setDisplayShowTitleEnabled(false); 

    //Set the choices on the spinner by setting the adapter. 
    spinner.setAdapter(new SpinnerAdapter(toolbar.getContext(), new String[]{"Overview", "Story", "Specifications", "Poll", "Video"}, accentColor, backgroundColor));

    //Set the text color of the Spinner's selected view (not a drop down list view)
    spinner.setSelection(0, true);
    View v = spinner.getSelectedView();
    ((TextView)v).setTextColor(backgroundColor);

    //Set the listener for when each option is clicked. 
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
    { 

        @Override 
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
        { 
           //Change the selected item's text color 
           ((TextView) view).setTextColor(backgroundColor);
        } 

        @Override 
        public void onNothingSelected(AdapterView<?> parent)
        { 
        } 
    }); 

} 

For more info on the source code of the setSelection methods, see the AbsSpinner.java code here: https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/java/android/widget/AbsSpinner.java

And here is Spinner.java in case it helps: https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/java/android/widget/Spinner.java