Создание setError() для Spinner
Как вы создаете setError()
(аналогично функции TextView/EditText
) для Spinner
? Не работает следующее:
Я попытался расширить класс Spinner и в конструкторе:
ArrayAdapter<String> aa = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item, android.R.id.text1,
items);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
setAdapter(aa);
tv = (TextView) findViewById(android.R.id.text1);
// types_layout_list_tv
ctv = (CheckedTextView) aa.getDropDownView(1, null, null);
tv2 = (TextView) aa.getView(1, null, null);
setError
метод:
public void setError(String str) {
if (tv != null)
tv.setError(str);
if(tv2!=null)
tv2.setError(str);
if (ctv != null)
ctv.setError(str);
}
Ответы
Ответ 1
Подобно решению @Gábor, но мне не нужно было создавать собственный адаптер. Я просто вызываю следующий код в моей функции проверки (т.е. Нажата кнопка отправки)
TextView errorText = (TextView)mySpinner.getSelectedView();
errorText.setError("anything here, just to add the icon");
errorText.setTextColor(Color.RED);//just to highlight that this is an error
errorText.setText("my actual error text");//changes the selected item text to this
Ответ 2
У меня есть решение, которое не требует создания дополнительного поля редактирования, но вам, как обычно, нужен собственный SpinnerAdapter
.
Убедитесь, что у вас есть хотя бы один TextView
в макете, который вы используете в своем адаптере getView()
(обычно это так).
Добавьте в свой адаптер следующую функцию (измените name
на идентификатор вашего TextView
):
public void setError(View v, CharSequence s) {
TextView name = (TextView) v.findViewById(R.id.name);
name.setError(s);
}
Вызвать setError()
из вашего кода таким образом:
YourAdapter adapter = (YourAdapter)spinner.getAdapter();
View view = spinner.getSelectedView();
adapter.setError(view, getActivity().getString(R.string.error_message));
В принципе, как и с любым другим элементом управления, только вы вызываете его на свой адаптер, и вы также должны предоставить представление.
Это отобразит значок ошибки на счетчике, как в случае с другими элементами управления.
Ответ 3
Использование скрытого TextView для отображения всплывающего сообщения
Это решение включает добавление дополнительного скрытого текстового поля чуть ниже счетчика только в правильном положении, чтобы отобразить диалоговое окно с отображением текста, в то же время используя TextView, установленный на XML-шаблоне Spinner, чтобы позволить красной (!) иконке отображается. Таким образом, используются два текстовых изображения: один для значка и другой (скрытый), чтобы разрешить диалог с ошибкой.
Это то, что выглядит, когда не в состоянии ошибки (используйте SetError(null)
):
![Spinner in valid state]()
Это то, что выглядит, когда есть ошибка (используйте SetError("my error text, ideally from a resource!")
):
![Spinner in invalid state]()
Вот выдержка из XML-шаблона Spinner. Существует RelativeLayout, используемый для обеспечения того, чтобы TextView был как можно ближе к счетчику, и имеет достаточно paddingRight, чтобы стрелка в диалоговом окне сообщения была выровнена под красной ошибкой (!). Скрытый (поддельный) TextView расположен относительно Spinner.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|left"
>
<Spinner
android:id="@+id/spnMySpinner"
android:layout_width="400dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:dropDownSelector="@drawable/selector_listview"
android:background="@android:drawable/btn_dropdown"
android:paddingBottom="0dp"
android:layout_marginBottom="0dp"
/>
<!-- Fake TextView to use to set in an error state to allow an error to be shown for the TextView -->
<android.widget.TextView
android:id="@+id/tvInvisibleError"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignRight="@+id/spnMySpinner"
android:layout_alignBottom="@+id/spnMySpinner"
android:layout_marginTop="0dp"
android:paddingTop="0dp"
android:paddingRight="50dp"
android:focusable="true"
android:focusableInTouchMode="true"
/>
</RelativeLayout>
Примечание: @drawable/selector_listview
определяется вне области действия этого решения. См. пример здесь о том, как заставить это работать, поскольку это не соответствует теме для этого ответа.
Вот код, чтобы заставить его работать. Просто вызовите SetError(errMsg)
либо с помощью null
, чтобы удалить ошибку, либо с текстом, чтобы установить его в состояние ошибки.
/**
* When a <code>errorMessage</code> is specified, pops up an error window with the message
* text, and creates an error icon in the secondary unit spinner. Error cleared through passing
* in a null string.
* @param errorMessage Error message to display, or null to clear.
*/
public void SetError(String errorMessage)
{
View view = spnMySpinner.getSelectedView();
// Set TextView in Secondary Unit spinner to be in error so that red (!) icon
// appears, and then shake control if in error
TextView tvListItem = (TextView)view;
// Set fake TextView to be in error so that the error message appears
TextView tvInvisibleError = (TextView)findViewById(R.id.tvInvisibleError);
// Shake and set error if in error state, otherwise clear error
if(errorMessage != null)
{
tvListItem.setError(errorMessage);
tvListItem.requestFocus();
// Shake the spinner to highlight that current selection
// is invalid -- SEE COMMENT BELOW
Animation shake = AnimationUtils.loadAnimation(this, R.anim.shake);
spnMySpinner.startAnimation(shake);
tvInvisibleError.requestFocus();
tvInvisibleError.setError(errorMessage);
}
else
{
tvListItem.setError(null);
tvInvisibleError.setError(null);
}
}
В приведенной выше функции SetError
, например, есть некоторый дополнительный код, который заставляет текст в Spinner дрожать, когда установлена ошибка. Это не требуется для того, чтобы решение работало, но это приятное дополнение. Смотрите здесь для вдохновения для этого подхода.
Kudos to @Gábor для его решение, которое использует TextView на макете элементов Spinner XML. Код View view = spnMySpinner.getSelectedView();
(на основе решения @Gábor) необходим, поскольку он получает отображаемый в настоящее время TextView вместо использования findViewById
, который просто получит первый TextView в списке (на основе предоставленного идентификатора ресурса) и, следовательно, не будет работать (для отображения красного (!) значка), если не выбран первый элемент в списке.
Ответ 4
Я предлагаю вам положить пустой EditText
прямо за спиннер.
В наборе xml, который EditText
android:enabled="false"
android:inputType="none"
Теперь, когда вы хотите установить ошибку на свой счетчик, просто установите эту ошибку в EditText
.
Не забудьте установить EditText
в invisibille
/gone
. Это не сработает.
Также обратите внимание, что с помощью этого метода вы можете точно определить, где именно должна появиться ваша ошибка.
Ответ 5
Это можно сделать без использования настраиваемого макета или адаптера.
((TextView)spinner.getChildAt(0)).setError("Message");
Единственным недостатком этого подхода является то, что небольшое всплывающее окно с текстом ошибки не будет отображаться при нажатии значка.
Ответ 6
Спасибо Габор за ваше фантастическое решение. В соответствии с вашим решением мое решение:
Пользовательский адаптер
public class RequiredSpinnerAdapter<T> extends ArrayAdapter<T> {
public RequiredSpinnerAdapter(Context context, int textViewResourceId,
java.util.List<T> objects) {
super(context, textViewResourceId, objects);
}
int textViewId = 0;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (view instanceof TextView) {
textViewId = view.getId();
}
return view;
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View row = super.getView(position, convertView, parent);
return (row);
}
public void setError(View v, CharSequence s) {
if(textViewId != 0){
TextView name = (TextView) v.findViewById(textViewId);
name.setError(s);
}
}
}
Использовать адаптер для Spinner
ArrayAdapter<String> arrayAdapter = new RequiredSpinnerAdapter<String>(PropertyAdd.this, R.layout.checked, status_arr);
marketstatus_spinner.setAdapter(arrayAdapter);
marketstatus_spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// Put code here
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// Put code here
}
});
Проверить правильность
private boolean checkValidation() {
if(marketstatus_spinner.getSelectedItem().toString().equals("")){
RequiredSpinnerAdapter adapter = (RequiredSpinnerAdapter)marketstatus_spinner.getAdapter();
View view = marketstatus_spinner.getSelectedView();
adapter.setError(view, "Please select a value");
return false;
}
}
Ответ 7
Я полагаю, что Spinner не подходит для установки этого метода. В случае Spinner вы должны выбрать одно значение, а значения в Spinner должны быть отфильтрованы на уровне вашего адаптера. Таким образом, пользователь может выбирать только те значения, которые находятся в Spinner.
Ответ 8
Вы можете создать свой собственный адаптер (расширяет BaseAdapter реализует SpinnerAdapter). Таким образом, вы можете получить доступ к TextViews, отображаемым в счетчике. (методы getView и createViewFromResource - пример: ArrayAdapter) Когда вы добавляете пустой элемент списка, чтобы позволить пользователю оставить поле пустым, пока оно не станет Обязательный (первый элемент в spinner), вы можете сохранить его TextView в качестве частного члена в адаптере. Затем, когда приходит время вызвать setError ( "..." ) из Activity или Fragment, вы можете вызвать его на адаптере, который может передать его в пустой TextView.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(position, convertView, parent, mTextViewId);
}
private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) {
View view;
TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
text = (TextView) view;
} catch (ClassCastException e) {
Log.e(TAG, "You must supply a resource ID for a TextView", e);
throw new IllegalStateException("MyAdapter requires the resource ID to be a TextView", e);
}
MyItem i = getItem(position);
String s = (null != i) ? i.toString() : "";
text.setText(s);
if ("".equals(s) && null == mEmptyText) {
this.mEmptyText = text;
}
return view;
}
public void setError(String errorMessage) {
if (null != mEmptyText) {
mEmptyText.setError(errorMessage);
} else {
Log.d(TAG, "mEmptyText is null");
}
}
Ответ 9
На самом деле это очень просто, вам просто нужно иметь только один TextView
в вашем представлении, а затем получить выбранный вид из вашего счетчика, используя getSelectedView()
, если основной вид в выбранном вами представлении - это TextView
, а затем непосредственно Настройте View на TextView
и setError
следующим образом:
((TextView) jobCategory.getSelectedView()).setError("Field Required");
Иначе, если Textview не является непосредственно MAIN View, вам нужно найти его по идентификатору и повторить его и setError
следующим образом:
((TextView) jobCategory.getSelectedView().findViewById(R.id.firstName)).setError("Field Required");