为Spinner创build一个setError()

你如何创build一个SpinnersetError() (类似于一个TextView/EditText )函数? 以下不起作用:

我试着扩展了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); } 

类似于@Gábor的解决scheme,但我不需要创build自己的适配器。 我只是在我的validationfunction(即点击提交button)中调用以下代码:

  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 

我有一个解决scheme,不涉及创build一个额外的编辑字段,但你需要自己的SpinnerAdapter ,像往常一样。

确保在适配器的getView()使用的布局中至less有一个TextView (无论如何,通常都是这样)。

将以下函数添加到适配器(将name更改为TextView的ID):

 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)); 

基本上和其他控件一样,只有你在你的适配器上调用它,你也必须提供视图。

这将显示微调框上的错误图标,与其他控件一样。

使用隐藏的TextView来显示popup消息

此解决scheme涉及在右侧位置添加一个额外的隐藏文本框,以允许显示TextView的错误对话框,同时还使用微调器布局XML上的TextView设置来显示红色(!)图标。 所以实际上,使用两个textview – 一个用于图标,另一个(隐藏)用于允许错误对话框。

这不是在错误状态(使用SetError(null) )时的样子:

微调在有效状态

这是什么时候出现错误(使用SetError("my error text, ideally from a resource!") ):

微调无效状态

这里是微调的布局XML的摘录。 有一个RelativeLayout用于确保TextView尽可能靠近微调器,并有足够的paddingRight来确保消息对话框中的箭头正好在红色错误(!)图标下alignment。 隐藏的(假的)TextView相对于微调器定位。

  <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定义在这个解决scheme的范围之外。 这里看例子如何得到这个工作,因为这是关于这个答案的主题。

这是使它工作的代码。 只需使用null调用SetError(errMsg)来清除错误,或者使用文本将其设置为错误状态。

 /** * 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函数中,有一些额外的代码会导致在设置错误时微调器中的文本抖动。 这不是必需的,使解决scheme的工作,但是一个很好的补充。 看到这里为这种方法的启发。

对@Gábor的赞誉是他的解决scheme ,它使用了Spinner项目布局XML上的TextView。 代码View view = spnMySpinner.getSelectedView(); (基于@Gábor的解决scheme)是必要的,因为它获取当前显示的TextView,而不是使用findViewById ,它只是获得列表中的第一个TextView(基于提供的资源ID),因此不会工作显示红色(!)图标),如果没有select列表中的第一个项目。

我build议你在你的微调器后面放一个空的EditText

关于EditText的xml设置

 android:enabled="false" android:inputType="none" 

现在,当您想要为您的微调器设置一个错误,只需将该错误设置为EditText

请记住不要将该EditText设置为invisibille / gone 。 它不会那样工作。

另外,请注意,通过这种方法,您可以确切地确定您的错误出现的位置。

这可以在不使用自定义布局或适配器的情况下完成。

 ((TextView)spinner.getChildAt(0)).setError("Message"); 

这种方法唯一的缺点是,当点击图标时,带有错误文本的小popup窗口不会显示。

感谢Gabor提供您绝妙的解决scheme。 为了进一步说明您的观点,我的解决scheme是:

自定义适配器

  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 } }); 

检查validation

 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; } } 

我想Spinner并不是放这个方法的好地方。 在Spinner的情况下,您应该select一个值,并且Spinner中的值应该在您的适配器级别进行过滤。 因此,用户只能select微调器中的那些值。

你可以创build你自己的适配器(扩展BaseAdapter实现SpinnerAdapter)。 这样,您可以访问在微调器中显示的TextViews。 (getView和createViewFromResource方法 – 例如: ArrayAdapter )当您添加一个空的列表项,以允许用户保持字段为空,直到它成为强制性的(微调框中的第一项),您可以将它的TextView作为私有成员存储在适配器。 然后,当需要从Activity或Fragment调用setError(“…”)时,可以在可以将它传递给空的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"); } } 

其实这是非常的,你只需要在你的视图中只有一个TextView ,然后使用getSelectedView()从你的微调获取选定的视图,如果你select的视图中的主视图是一个TextView然后直接将视图转换为TextViewsetError喜欢这个 :

 ((TextView) jobCategory.getSelectedView()).setError("Field Required"); 

否则,如果Textview不是直接的MAIN视图,那么你需要通过IDfind它,并再次投下它,并setError这样:

  ((TextView) jobCategory.getSelectedView().findViewById(R.id.firstName)).setError("Field Required");