Компонент Spinner предоставляет быстрый способ выбора значения из предложенного списка с вариантами. Поскольку список выводится только при нажатии на спиннер, это экономит место на экране вашего устройства. В состоянии по умолчанию спиннер отображает текущее значение. Если же коснуться компонента, то появится выпадающее меню со всеми другими доступными значениями, из которых пользователь может выбрать нужное ему.
Например, когда вы пользуетесь галереей на своём устройстве, вы используете спиннер, чтобы выбрать, какую категорию или папку нужно отобразить.
Создадим свой собственный спиннер со своей разметкой. Он будет содержать список стран с флагами. Для начала создадим в Android Studio новый проект, внутри которого в файл activity_main.xml поместим следующий код:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/myTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp"/> <Spinner android:id="@+id/SpinnerCustom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp"/> </LinearLayout>
Затем добавим вспомогательный класс CountyInfo, с помощью которого будем заполнять спиннер данными.
В данном случае нам будут нужны:
- Название страны;
- Флаг;
- Численность населения.
В списке будут отображаться только флаг и название страны, затем при выборе в отдельном TextView будет выведена полная информация вместе с численностью населения. Данные захардкожены, однако если есть желание, можно добавить возможность вводить данные вручную пользователям.
public class CountryInfo { private String countryName; private long countryPopulation; private int countryFlag; public CountryInfo(String cName, long cPopulation, int flagImage) { countryName = cName; countryPopulation = cPopulation; countryFlag = flagImage; } public String getCountryName() { return countryName; } public long getCountryPopulation() { return countryPopulation; } public int getCountryFlag() { return countryFlag; } public String toString() { return countryName; } }
Кроме того, нам нужен адаптер, в котором записи будут храниться. Для этого создадим класс CountryAdapter, наследующий ArrayAdapter<CountryInfo> со следующим кодом:
public class CountryAdapter extends ArrayAdapter<CountryInfo> { private Activity context; ArrayList<CountryInfo> data = null; public CountryAdapter(Activity context, int resource, ArrayList<CountryInfo> data) { super(context, resource, data); this.context = context; this.data = data; } @Override @NonNull public View getView(int position, View convertView, @NonNull ViewGroup parent) { return super.getView(position, convertView, parent); } @Override public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) { // этот код выполняется, когда вы нажимаете на спиннер View row = convertView; if (row == null) { LayoutInflater inflater = context.getLayoutInflater(); row = inflater.inflate(R.layout.spinner_layout, parent, false); } CountryInfo item = data.get(position); if (item != null) { // парсим данные с каждого объекта ImageView myFlag = (ImageView) row.findViewById(R.id.imageIcon); TextView myCountry = (TextView) row.findViewById(R.id.countryName); if (myFlag != null) { myFlag.setBackground(context.getResources().getDrawable(item.getCountryFlag(), context.getTheme())); } if (myCountry != null) myCountry.setText(item.getCountryName()); } return row; } }
В методе getDropDownView() создаётся собственный макет для установки нужных ImageView и TextView.
В классе главной активности добавим следующий код, который будет реализовывать наш спиннер. Предварительно нужно найти флаги стран и добавить их в папку drawable нашего проекта.
Spinner mySpinner; TextView myTextView; ArrayList<CountryInfo> myCountries; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myCountries = populateList(); setContentView(R.layout.activity_main); mySpinner = (Spinner) findViewById(R.id.SpinnerCustom); myTextView = (TextView) findViewById(R.id.myTextView); CountryAdapter myAdapter = new CountryAdapter(this, android.R.layout.simple_spinner_item, myCountries); mySpinner.setAdapter(myAdapter); mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { CountryInfo myCountry; if (mySpinner.getSelectedItem() != null) { myCountry = (CountryInfo) mySpinner.getSelectedItem(); myTextView.setText(String.format("Страна: " + myCountry.getCountryName() + "\nЧисленность населения: " + myCountry.getCountryPopulation())); } } @Override public void onNothingSelected(AdapterView<?> adapterView) { } }); } public ArrayList<CountryInfo> populateList() { ArrayList<CountryInfo> myCountries = new ArrayList<CountryInfo>(); myCountries.add(new CountryInfo("США", 308745538, R.drawable.usa)); myCountries.add(new CountryInfo("Россия", 9482855, R.drawable.russia)); myCountries.add(new CountryInfo("Канада", 34018000, R.drawable.canada)); return myCountries; }
Метод populateList() используется для того, чтобы заполнить наш спиннер данными о странах.
Теперь нужно добавить разметку для будущего спиннера. Чтобы это сделать, нужно в layout добавить файл spinner_layout.xml со следующим кодом:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/bluegradient" android:orientation="horizontal"> <ImageView android:id="@+id/imageIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/canada" /> <TextView android:id="@+id/countryName" android:layout_width="match_parent" android:layout_height="match_parent" android:ellipsize="marquee" android:gravity="center" android:maxLines="1" android:textColor="@android:color/white" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> </LinearLayout>
У элемента LinearLayout в свойстве background указан ресурс drawable, он используется для того, чтобы задать градиент для спиннера. Создадим файл bluegradient.xml в папке drawable со следующим кодом:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > <shape> <solid android:color="#2183b0" /> <stroke android:width="1dp" android:color="#adc6e8" /> <corners android:radius="4dp" /> <padding android:left="4dp" android:top="4dp" android:right="4dp" android:bottom="4dp" /> </shape> </item> <item> <shape> <gradient android:startColor="#2183b0" android:endColor="#7cbfde" android:angle="270" android:type="linear" /> <stroke android:width="1dp" android:color="#2183b0" /> <corners android:radius="4dp" /> <padding android:left="0dp" android:top="4dp" android:right="0dp" android:bottom="4dp" /> </shape> </item> </selector>
В результате всех проделанных манипуляций мы получили красивый раскрывающийся список со странами.
Кроме того, при изменении выбранного элемента в списке, происходит обновление текстового поля.
У компонента Spinner в Android существуют два способа отображения, которые можно задать в файле разметки:
- dropdown;
- dialog.
В примере выше был показан первый вариант, когда спиннер отображается в приложении в виде выпадающего списка. Теперь модифицируем приложение, чтобы список выводился в диалоговом окне. Для этого в файле activity_main.xml в тэге <Spinner> допишем новое свойство:
android:spinnerMode="dialog"
Данное свойство изменит способ отображения спиннера. По умолчанию, значение spinnerMode равно dropdown. Посмотрим, как изменился наш спинер.
Поскольку Spinner можно разместить в любом месте в приложении, это также можно сделать и в тулбаре (Toolbar), как вы, возможно, видели в приложениях Галерея и Gmail на своём устройстве. Для этого вставим в activity_main.xml следующий код перед <TextView>:
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimaryDark" android:minHeight="?attr/actionBarSize" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:elevation="4dp"> <Spinner android:id="@+id/SpinnerNav" android:layout_width="wrap_content" android:layout_height="wrap_content" android:popupTheme="@style/ThemeOverlay.AppCompat.Dark" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/> </android.support.v7.widget.Toolbar>
Таким образом мы объявили свой собственный тулбар и разместили на нём ещё один спиннер. Теперь нужно убрать тулбар, предоставляемый темой приложения, для этого зайдём в файл styles.xml и изменим значение parent у нашей темы. В итоге должно получится примерно следующее:
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
Теперь в классе активности добавим тулбар и спиннер, и установим ему адаптер. Для этого объявим их:
Spinner navSpinner; Toolbar toolbar;
Затем инициализируем после метода setContentView() в onCreate():
navSpinner = (Spinner) findViewById(R.id.SpinnerNav); toolbar = (Toolbar) findViewById(R.id.toolbar);
В заключение после mySpinner.setAdapter(myAdapter); установим адаптер и второму спиннеру:
navSpinner.setAdapter(myAdapter);
Теперь мы можем запустить наше приложение и убедиться, что на тулбаре заместо названия приложения теперь находится созданный спиннер. При желании ему также можно назначить OnItemSelectedListener, который будет менять текст на активности при смене значения.