Как установить значение по умолчанию Spinner на NULL?
-
12-10-2019 - |
Вопрос
Я пытаюсь заставить спиннер для загрузки без выбранного значения. Как только пользователь выбирает значение, он доставит их на другую страницу.
Это оказывается проблемой, потому что в настоящее время страница просто загружается сразу, прежде чем пользователь получит выбор для выбора.
Мой класс Spinner настроен так же, как Google: http://developer.android.com/resources/tutorials/views/hello-spinner.html
Таким образом, в основном возможно, иметь прядильщик, который загружается ни с чем не выбранным, потому что в настоящее время он загружает первый элемент в мой строковый массив.
Решение
Возможно ли иметь прядильщик, который загружается ни с чем не выбранным
Только если нет данных. Если у вас есть 1+ элемента в SpinnerAdapter
, Spinner
всегда будет выбор.
Spinners
не предназначены для командных виджетов. Пользователи не ожидают выбора в Spinner
Чтобы начать деятельность. Пожалуйста, рассмотрите возможность использования чего -то другого, например ListView
или же GridView
, вместо Spinner
.
РЕДАКТИРОВАТЬ
Кстати, я забыл упомянуть - вы всегда можете поместить дополнительную запись в свой адаптер, который представляет «без выбора», и сделать его первоначальным выбранным элементом в Spinner
.
Другие советы
В качестве альтернативы, вы можете переопределить адаптер прядильщика и предоставить пустое представление для позиции 0 в вашем методе GetView и представление с высотой 0DP в getDropDownView
метод
Таким образом, у вас есть начальный текст, такой как «Выберите опцию ...», который отображается, когда прядильщик сначала загружен, но для пользователя это не вариант (технически это так, но потому что высота 0 , они не видят этого).
Это полная реализация Идея Пола Бурдо, а именно возврат специального начального представления (или пустого представления) в getView()
для позиции 0.
Это работает для меня и относительно просто. Вы можете считать этот подход особенно Если у вас уже есть пользовательский адаптер для вашего прядильщика. (В моем случае я использовал пользовательский адаптер, чтобы легко настроить макет элементов, каждый элемент имеет пару текстовых обзоров.)
Адаптер будет чем -то в этом направлении:
public class MySpinnerAdapter extends ArrayAdapter<MyModel> {
public MySpinnerAdapter(Context context, List<MyModel> items) {
super(context, R.layout.my_spinner_row, items);
}
@Override
public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
if (position == 0) {
return initialSelection(true);
}
return getCustomView(position, convertView, parent);
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
if (position == 0) {
return initialSelection(false);
}
return getCustomView(position, convertView, parent);
}
@Override
public int getCount() {
return super.getCount() + 1; // Adjust for initial selection item
}
private View initialSelection(boolean dropdown) {
// Just an example using a simple TextView. Create whatever default view
// to suit your needs, inflating a separate layout if it's cleaner.
TextView view = new TextView(getContext());
view.setText(R.string.select_one);
int spacing = getContext().getResources().getDimensionPixelSize(R.dimen.spacing_smaller);
view.setPadding(0, spacing, 0, spacing);
if (dropdown) { // Hidden when the dropdown is opened
view.setHeight(0);
}
return view;
}
private View getCustomView(int position, View convertView, ViewGroup parent) {
// Distinguish "real" spinner items (that can be reused) from initial selection item
View row = convertView != null && !(convertView instanceof TextView)
? convertView :
LayoutInflater.from(getContext()).inflate(R.layout.my_spinner_row, parent, false);
position = position - 1; // Adjust for initial selection item
MyModel item = getItem(position);
// ... Resolve views & populate with data ...
return row;
}
}
Вот и все. Обратите внимание, что если вы используете OnItemSelectedListener
с вашим спиннером, в onItemSelected()
Вам также придется отрегулировать position
Чтобы принять во внимание элемент по умолчанию, например:
if (position == 0) {
return;
} else {
position = position - 1;
}
MyModel selected = items.get(position);
В моем случае, хотя размер 2 'отображается в спиннере, ничего не происходит, пока не будет сделан какой -то выбор!
У меня есть XML -файл (data_sizes.xml), в котором перечислены все значения прядильщиков.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chunks">
<item>2</item>
<item>4</item>
<item>8</item>
<item>16</item>
<item>32</item>
</string-array>
</resources>
В файле main.xml: Spinner Element
<Spinner android:id="@+id/spinnerSize"
android:layout_marginLeft="50px"
android:layout_width="fill_parent"
android:drawSelectorOnTop="true"
android:layout_marginTop="5dip"
android:prompt="@string/SelectSize"
android:layout_marginRight="30px"
android:layout_height="35px" />
Затем в моем коде Java я добавил:
В моей деятельности: объявление
Spinner spinnerSize;
ArrayAdapter adapter;
В публичной недействительной функции - initControls (): определение
spinnerSize = (Spinner)findViewById(R.id.spinnerSize);
adapter = ArrayAdapter.createFromResource(this, R.array.chunks, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerSize.setAdapter(adapter);
spinnerSize.setOnItemSelectedListener(new MyOnItemSelectedListener());
Мой спиннер слушатель:
/ * Слушатель спиннера */
class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
chunkSize = new Integer(parent.getItemAtPosition(pos).toString()).intValue();
}
public void onNothingSelected(AdapterView<?> parent) {
// Dummy
}
}
Используя пользовательский макет спиннера, как это:
<?xml version="1.0" encoding="utf-8"?>
<Spinner xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/spinnerTarget"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14dp"
android:textColor="#000000"/>
В деятельности:
// populate the list
ArrayList<String> dataList = new ArrayList<String>();
for (int i = 0; i < 4; i++) {
dataList.add("Item");
}
// set custom layout spinner_layout.xml and adapter
Spinner spinnerObject = (Spinner) findViewById(R.id.spinnerObject);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, R.drawable.spinner_layout, dataList);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerObject.setAdapter(dataAdapter);
spinnerObject.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// to set value of first selection, because setOnItemSelectedListener will not dispatch if the user selects first element
TextView spinnerTarget = (TextView)v.findViewById(R.id.spinnerTarget);
spinnerTarget.setText(spinnerObject.getSelectedItem().toString());
return false;
}
});
spinnerObject.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
private boolean selectionControl = true;
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// just the first time
if(selectionControl){
// find TextView in layout
TextView spinnerTarget = (TextView)parent.findViewById(R.id.spinnerTarget);
// set spinner text empty
spinnerTarget.setText("");
selectionControl = false;
}
else{
// select object
}
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
Объедините это:
private long previousItemId = 0;
@Override
public long getItemId(int position) {
long nextItemId = random.nextInt(Integer.MAX_VALUE);
while(previousItemId == nextItemId) {
nextItemId = random.nextInt(Integer.MAX_VALUE);
}
previousItemId = nextItemId;
return nextItemId;
}
С этим отвечать:
public class SpinnerInteractionListener
implements AdapterView.OnItemSelectedListener, View.OnTouchListener {
private AdapterView.OnItemSelectedListener onItemSelectedListener;
public SpinnerInteractionListener(AdapterView.OnItemSelectedListener selectedListener) {
this.onItemSelectedListener = selectedListener;
}
boolean userSelect = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
userSelect = true;
return false;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if(userSelect) {
onItemSelectedListener.onItemSelected(parent, view, pos, id);
userSelect = false;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
if(userSelect) {
onItemSelectedListener.onNothingSelected(parent);
userSelect = false;
}
}
}
Вы можете поместить первую ячейку в свой массив, чтобы быть пустой ({"", "немного", "немного", ...}) и ничего не делать, если позиция составляет 0;
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(position>0) {
label.setText(MainActivity.questions[position - 1]);
}
}
- Если вы заполняете массив файлом XML, вы можете дать первый элемент опустошенным
Мое решение, если у вас есть TextView в качестве каждой строки спиннера:
// TODO: add a fake item as the last one of "items"
final ArrayAdapter<String> adapter=new ArrayAdapter<String>(..,..,items)
{
@Override
public View getDropDownView(final int position,final View convertView,final ViewGroup parent)
{
final View dropDownView=super.getDropDownView(position,convertView,parent);
((TextView)dropDownView.findViewById(android.R.id.text1)).setHeight(position==getCount()-1?0:getDimensionFromAttribute(..,R.attr.dropdownListPreferredItemHeight));
dropDownView.getLayoutParams().height=position==getCount()-1?0:LayoutParams.MATCH_PARENT;
return dropDownView;
}
}
...
spinner.setAdapter(adapter);
_actionModeSpinnerView.setSelection(dataAdapter.getCount()-1,false);
public static int getDimensionFromAttribute(final Context context,final int attr)
{
final TypedValue typedValue=new TypedValue();
if(context.getTheme().resolveAttribute(attr,typedValue,true))
return TypedValue.complexToDimensionPixelSize(typedValue.data,context.getResources().getDisplayMetrics());
return 0;
}
База на @jonik answer Я создал полностью функциональное расширение в ArrayAdapter
class SpinnerArrayAdapter<T> : ArrayAdapter<T> {
private val selectText : String
private val resource: Int
private val fieldId : Int
private val inflater : LayoutInflater
constructor(context: Context?, resource: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = 0
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource : Int, objects: List<T>, selectText : String? = null) : super(context, resource, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = 0
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource: Int, textViewResourceId: Int, objects: Array<T>, selectText : String? = null) : super(context, resource, textViewResourceId, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = textViewResourceId
this.inflater = LayoutInflater.from(context)
}
constructor(context: Context?, resource : Int, textViewResourceId: Int, objects: List<T>, selectText : String? = null) : super(context, resource, textViewResourceId, objects) {
this.selectText = selectText ?: context?.getString(R.string.spinner_default_select_text) ?: ""
this.resource = resource
this.fieldId = textViewResourceId
this.inflater = LayoutInflater.from(context)
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup?): View {
if(position == 0) {
return initialSelection(true)
}
return createViewFromResource(inflater, position -1, convertView, parent, resource)
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
if(position == 0) {
return initialSelection(false)
}
return createViewFromResource(inflater, position -1, convertView, parent, resource)
}
override fun getCount(): Int {
return super.getCount() + 1 // adjust for initial selection
}
private fun initialSelection(inDropDown: Boolean) : View {
// Just simple TextView as initial selection.
val view = TextView(context)
view.setText(selectText)
view.setPadding(8, 0, 8, 0)
if(inDropDown) {
// Hide when dropdown is open
view.height = 0
}
return view
}
private fun createViewFromResource(inflater: LayoutInflater, position: Int,
@Nullable convertView: View?, parent: ViewGroup?, resource: Int): View {
val view: View
val text: TextView?
if (convertView == null || (convertView is TextView)) {
view = inflater.inflate(resource, parent, false)
} else {
view = convertView
}
try {
if (fieldId === 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = view as TextView
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(fieldId)
if (text == null) {
throw RuntimeException("Failed to find view with ID "
+ context.getResources().getResourceName(fieldId)
+ " in item layout")
}
}
} catch (e: ClassCastException) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView")
throw IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e)
}
val item = getItem(position)
if (item is CharSequence) {
text.text = item
} else {
text.text = item!!.toString()
}
return view
}
Я предполагаю, что вы хотите иметь Spinner
с первым пустым невидимым предметом (это странная особенность Spinner
Это не может показать список без выбора элемента). Вы должны добавить класс, который будет содержать данные:
data class YourData(val id: Int, val name: String?)
Это адаптер.
class YourAdapter(
context: Context,
private val textViewResourceId: Int,
private var items: ArrayList<YourData>
) : ArrayAdapter<YourData>(context, textViewResourceId, items) {
private var inflater: LayoutInflater = context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
override fun getCount(): Int = items.size + 1
override fun getItem(position: Int): YourData? =
if (position == 0) YourData(0, "") else items[position - 1]
override fun getItemId(position: Int): Long = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View =
if (position == 0) {
getFirstTextView(convertView)
} else {
getTextView(convertView, parent, position - 1)
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View =
getView(position, convertView, parent)
private fun getFirstTextView(convertView: View?): View {
// Just simple TextView as initial selection.
var textView: TextView? = convertView as? TextView
val holder: FirstViewHolder
if (textView?.tag !is FirstViewHolder) {
textView = TextView(context) // inflater.inflate(R.layout.your_text, parent, false) as TextView
textView.height = 0 // Hide first item.
holder = FirstViewHolder()
holder.textView = textView
textView.tag = holder
}
return textView
}
private fun getTextView(
convertView: View?,
parent: ViewGroup,
position: Int
): TextView {
var textView: TextView? = convertView as? TextView
val holder: ViewHolder
if (textView?.tag is ViewHolder) {
holder = textView.tag as ViewHolder
} else {
textView = inflater.inflate(textViewResourceId, parent, false) as TextView
holder = ViewHolder()
holder.textView = textView
textView.tag = holder
}
holder.textView.text = items[position].name
return textView
}
private class FirstViewHolder {
lateinit var textView: TextView
}
private class ViewHolder {
lateinit var textView: TextView
}
}
Создавать:
YourAdapter(context!!, R.layout.text_item, ArrayList())
Чтобы добавить элементы:
private fun fill(items: List<YourData>, adapter: YourAdapter) {
adapter.run {
clear()
addAll(items)
notifyDataSetChanged()
}
}
Когда вы загружаете элементы в свой Spinner
с этим fill()
Команда, вы должны знать, что индексы также увеличены. Поэтому, если вы хотите выбрать 3 -й элемент, теперь вы должны выбрать 4 -е: spinner?.setSelection(index + 1)