我正在寻找一种方法来隐藏Android微调框小部件中的一个项目。这将允许您模拟没有选择项目的微调器,并确保始终为所选的每个项目调用onItemSelected()回调(如果隐藏项目是“当前”项目)。通常,微调器中总有一个项不会生成回调,即当前的回调。
stackoverflow上有一些关于如何禁用(灰显)项目的代码,而不是如何完全隐藏项目,就好像它们不存在一样。
经过多次实验,我想出了一个适用于各种新旧Android平台的黑客解决方案。它有一些小的化妆品缺点,很难注意到。我仍然希望听到一个更正式的解决方案,除了“不要用旋转器做那个”。
这总是隐藏微调器中的第一个项目,但可以相当容易地扩展以隐藏任意项目或多个项目。在微调器项列表的开头添加一个包含空字符串的虚拟项。您可能希望在微调器对话框打开之前将当前微调器选择设置为项目0,这将模拟未选择的微调器。
使用ArrayAdapter方法的Spinner设置示例覆盖:
List<String> list = new ArrayList<String>();
list.add(""); // Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");
// Populate the spinner using a customized ArrayAdapter that hides the first (dummy) entry
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
View v = null;
// If this is the initial dummy entry, make it hidden
if (position == 0) {
TextView tv = new TextView(getContext());
tv.setHeight(0);
tv.setVisibility(View.GONE);
v = tv;
}
else {
// Pass convertView as null to prevent reuse of special case views
v = super.getDropDownView(position, null, parent);
}
// Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling
parent.setVerticalScrollBarEnabled(false);
return v;
}
};
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
答案 0 :(得分:45)
要隐藏任意项目或多个项目,我认为您可以实现自己的适配器并设置要隐藏的索引(或索引数组列表)。
public class CustomAdapter extends ArrayAdapter<String> {
private int hidingItemIndex;
public CustomAdapter(Context context, int textViewResourceId, String[] objects, int hidingItemIndex) {
super(context, textViewResourceId, objects);
this.hidingItemIndex = hidingItemIndex;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View v = null;
if (position == hidingItemIndex) {
TextView tv = new TextView(getContext());
tv.setVisibility(View.GONE);
v = tv;
} else {
v = super.getDropDownView(position, null, parent);
}
return v;
}
}
在创建项目列表时使用自定义适配器。
List<String> list = new ArrayList<String>();
list.add(""); // Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");
int hidingItemIndex = 0;
CustomAdapter dataAdapter = new CustomAdapter(this, android.R.layout.simple_spinner_item, list, hidingItemIndex);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
(我没有测试过代码)希望有所帮助。
答案 1 :(得分:18)
通过截断列表,可以更轻松地隐藏列表末尾的项目。
但是你必须先选择它,使其出现在微调器中,然后检查选择是否已更改为显示的其中一个项目。
List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
@Override
public int getCount() {
return(listsize); // Truncate the list
}
};
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
mySpinner.setSelection(listsize); // Hidden item to appear in the spinner
答案 2 :(得分:4)
要隐藏微调器下拉列表中的任何项目,您需要根据所需条件传递需要隐藏的项目位置。 我在隐藏从下拉列表中选择的项目的用例中实现了这一点
public class CustomAdapter extends ArrayAdapter<String> {
private List<String> dates;
private int hideItemPostion;
public CustomAdapter (Context context, int resource, List<String> dates) {
super(context, resource,dates);
this.dates=dates;
}
public void setItemToHide(int itemToHide)
{
this.hideItemPostion =itemToHide;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View v = null;
if (position == hideItemPostion) {
TextView tv = new TextView(getContext());
tv.setVisibility(View.GONE);
tv.setHeight(0);
v = tv;
v.setVisibility(View.GONE);
}
else
v = super.getDropDownView(position, null, parent);
return v;
}}
设置适配器就像这样
final CustomAdapter dataAdapter = new CustomAdapter(this,R.layout.spinner_item,dates);
dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
spinner.setAdapter(dataAdapter);
dataAdapter.setItemToHide(0);
从下拉列表中选择一些项目时,还需要更改位置
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, final int i, long l) {
dataAdapter.notifyDataSetChanged();
mEPGDateSelector.setSelection(i);
dataAdapter.setItemToHide(i);}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
答案 3 :(得分:1)
为了兴趣,我提出了一个解决方案,使用“提示”作为提示。此代码是为Xamarin.Android
生成的,但可以在10分钟内完美地移植到Java。像简单ArrayAdapter
一样使用它而不向源数组添加0索引或计数索引项。如果未选择任何内容,它还会将SpinnerGeolocation.SelectedItemId
设置为-1(hint
是当前项目。)
public class ArrayAdapterWithHint<T>: ArrayAdapter<T>
{
protected bool HintIsSet = false;
protected int HintResource = 0;
public ArrayAdapterWithHint(Context context, int textViewResourceId,
T[] objects)
: base(context, textViewResourceId, objects)
{
}
public ArrayAdapterWithHint(Context context, int hintResource,
int textViewResourceId, T[] objects)
: base(context, textViewResourceId, objects)
{
HintResource = hintResource;
}
public ArrayAdapterWithHint(Context context, int textViewResourceId,
IList<T> objects)
: base(context, textViewResourceId, objects)
{
}
public ArrayAdapterWithHint(Context context, int hintResource,
int textViewResourceId, IList<T> objects)
: base(context, textViewResourceId, objects)
{
HintResource = hintResource;
}
public override View GetDropDownView(int position, View convertView,
ViewGroup parent)
{
if (HintIsSet)
return base.GetDropDownView(position + 1,
convertView, parent);
return base.GetDropDownView(position, convertView, parent);
}
public override View GetView(int position, View convertView,
ViewGroup parent)
{
if (!HintIsSet && parent is Spinner &&
!string.IsNullOrWhiteSpace((parent as Spinner).Prompt))
{
Insert((parent as Spinner).Prompt, 0);
HintIsSet = true;
(parent as Spinner).SetSelection(base.Count - 1);
}
if (HintIsSet && position >= base.Count - 1)
{
View hintView = base.GetView(0, convertView, parent);
if (hintView is TextView)
(hintView as TextView).SetTextAppearance(
Context, HintResource);
return hintView;
}
if (HintIsSet && position < base.Count - 1)
return base.GetView(position + 1, convertView, parent);
return base.GetView(position, convertView, parent);
}
public override long GetItemId(int position)
{
if (HintIsSet)
{
if (position >= base.Count - 1)
return -1;
return position;
}
return base.GetItemId(position);
}
public override int Count
{
get
{
return base.Count > 0 && HintIsSet ? base.Count - 1 : base.Count;
}
}
}
答案 4 :(得分:1)
我找到了解决我问题的解决方案。
final Spinner mySpinner = (Spinner)findViewById(R.id.spinner_triptype);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, R.id.weekofday, triptype_initial);
final ArrayAdapter<String> adapter_temp = new ArrayAdapter<String>
(this,R.layout.spinner_item, R.id.weekofday, triptype_array);
mySpinner.setAdapter(adapter);
mySpinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// display your error popup here
if(flag_spinner_isFirst){
mySpinner.setAdapter(adapter_temp);
flag_spinner_isFirst = false;
}
v.onTouchEvent(event);
return true;
}
});
答案 5 :(得分:0)
我认为最好将验证放在数组列表而不是Spinner上,因为一旦过滤了项目,就可以安全地在Spinner中添加
答案 6 :(得分:0)
另一种最适合我的方法是返回一个新的空白视图对象。这是一个相当干净的方法,因为你没有玩数组元素。
创建扩展ArrayAdapter
在你的方法中
public View getView(int position, View convertView, ViewGroup parent) {
View row = getCustomView();
if(position==0) // put the desired check here.
{
row = new View(context);
}
}
return row;
}
答案 7 :(得分:0)
这是一个非常老的问题,但我发现了一种不错的(并且很可能是干净的)方式来不显示首个项目。 受@Romich的回答启发,我添加了类似的逻辑来跳过第一项。
这有效地隐藏了任意数量的项目(默认为1)。该代码仅报告要渲染的对象的大小小于实际大小,并且还更改了要渲染的项目的索引,因此我们跳过了任意数量的项目。
为简单起见,我排除了我目前使用的解决方案,该解决方案支持隐藏随机项目列表,但是只需对代码进行一些调整即可轻松解决该问题。
class ArrayAdapterCustom(context: Context, textViewResourceId: Int, vararg objects: String)
: ArrayAdapter<String>(context, textViewResourceId, objects) {
//Can skip first n items (skip 1 as default)
var hideFirstItemsCount = 1
override fun getCount(): Int {
return super.getCount() - hideFirstItemsCount
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
return super.getDropDownView(position + hideFirstItemsCount, convertView, parent)
}
}
答案 8 :(得分:0)
无需调整模型的更好方法。
public class HidableSpinnerArrayAdapter<T> extends ArrayAdapter<T> {
...
@Override
public boolean isEnabled(int position) {
// override this check what items are enabled/disabled
}
// Change color item
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// when hiding items, cannot reuse views
View view = super.getDropDownView(position,
null /* convertView usually */, parent);
if (!isEnabled(position)) {
TextView tv = (TextView) view;
tv.setEnabled(false);
tv.setMaxHeight(0);
tv.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
return tv;
}
else {
return view;
}
}
}