Использование скрытого TextView для отображения всплывающего сообщения
Это решение включает в себя добавление дополнительного скрытого текстового поля чуть ниже вращающегося элемента в правильном положении, чтобы можно было отобразить диалоговое окно ошибки TextView, в то же время также используя TextView, установленный в XML макета счетчика, чтобы красный (!) Значок отображался отображается. Таким образом, в действительности используются два текстовых представления - одно для значка, а другое (скрытое) для разрешения диалога об ошибке.
Вот как это выглядит, когда нет ошибки (используйте SetError(null)
):
Вот как это выглядит при возникновении ошибки (используйте SetError("my error text, ideally from a resource!")
):
Вот выдержка из макета блесны XML. Существует 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 при установке ошибки. Это не обязательно, чтобы решение работало, но это хорошее дополнение. См. Здесь для вдохновения для этого подхода.
Спасибо @ Gábor за его решение , которое использует TextView в XML макета элемента Spinner. Код View view = spnMySpinner.getSelectedView();
(основанный на решении @ Gábor) необходим, поскольку он получает отображаемый в данный момент TextView, а не использует findViewById
, который просто получит первый TextView в списке (на основе предоставленного идентификатора ресурса), и, следовательно, не будет работать (для отображения красного (!) значка), если самый первый элемент в списке не выбран.