我正在尝试为微调器实现“更多”按钮。基本上我想首先只显示几个项目,当用户点击最后一项(“更多...”)时,微调器将更改并显示所有项目。
因此,我需要的功能是一种动态更改微调器项而无需关闭微调器的方法。除了最后一部分,我已经成功完成了所有工作。每次我更改项目时,微调器都会自动关闭(不会失去焦点)。
我认为唯一的解决方法是使用Cell_Style
在关闭后立即打开微调器。当然,这还不够好,因为我得到了这种快速的重新开启效果。不酷。
我创建了一个管理逻辑的自定义微调器类:
mSpinner.performClick()
和自定义适配器:
public class ReservationStatusSpinner extends Spinner {
// --------------------------------------------------
// State
// --------------------------------------------------
private final String mMoreStatus;
private OnItemSelectedListener mUserListener;
private ArrayAdapter<String> mAdapter;
private boolean mOpenInitiated = false;
// --------------------------------------------------
// Interfaces
// --------------------------------------------------
private interface OnSpinnerEventsListener {
// Not needed, but may be needed in the future -> void onSpinnerOpened();
void onSpinnerClosed();
}
private OnSpinnerEventsListener mOnSpinnerEventsListener;
public interface OnStatusSelectedListener {
void onStatusSelected(String status);
}
private OnStatusSelectedListener mOnStatusSelectedListener;
// --------------------------------------------------
// Construction/Initialization
// --------------------------------------------------
public ReservationStatusSpinner(Context context) {
super(context);
mMoreStatus = getContext().getResources().getString(R.string.status_more);
init();
}
public ReservationStatusSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
mMoreStatus = getContext().getResources().getString(R.string.status_more);
init();
}
private void init() {
// Add listener
super.setOnItemSelectedListener(new OnItemSelected());
mOnSpinnerEventsListener = new OnSpinnerEventsListener() {
@Override
public void onSpinnerClosed() {
filterAndSelect();
}
};
}
// --------------------------------------------------
// Overridden methods
// --------------------------------------------------
@Override
public boolean performClick() {
// register that the Spinner was opened so we have a status
// indicator for the activity(which may lose focus for some other
// reasons)
mOpenInitiated = true;
return super.performClick();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// mSpin is our custom Spinner
if (mOpenInitiated && hasFocus) {
performClosedEvent();
}
}
@Override
public void setOnItemSelectedListener(OnItemSelectedListener l) {
mUserListener = l;
}
// --------------------------------------------------
// Private methods
// --------------------------------------------------
private static ArrayList<String> getAllStatuses(Context context) {
ArrayList<String> items = new ArrayList<>();
CharSequence[] statusesCSArray = context.getResources().getTextArray(R.array.reservation_status);
for (CharSequence cs : statusesCSArray)
items.add(cs.toString());
return items;
}
private void performClosedEvent() {
mOpenInitiated = false;
if (mOnSpinnerEventsListener != null) {
mOnSpinnerEventsListener.onSpinnerClosed();
}
}
private void filterAndSelect() {
List<String> items = filterStatuses((String)getSelectedItem(), mMoreStatus);
setItems(items);
setSelection(0);
}
// --------------------------------------------------
// Public methods
// --------------------------------------------------
public void setStatus(String status) {
// Find status in adapter
int pos = -1;
for (int i = 0; i < mAdapter.getCount(); ++i) {
if (mAdapter.getItem(i).equals(status)) {
pos = i;
break;
}
}
if (pos != -1)
setSelection(pos);
}
public void setAdapter(ArrayAdapter<String> adapter) {
super.setAdapter(adapter);
mAdapter = adapter;
}
public void setOnStatusSelectedListener(OnStatusSelectedListener l) {
mOnStatusSelectedListener = l;
}
public void setItems(List<String> items) {
mAdapter.clear();
mAdapter.addAll(items);
mAdapter.notifyDataSetChanged();
}
// --------------------------------------------------
// Utilities
// --------------------------------------------------
public static ArrayList<String> filterStatuses(String selectedStatus, String moreStatus) {
ArrayList<String> list = new ArrayList<>(DataUtilities.filterStatuses(selectedStatus));
// Add selected status at start
list.add(0, selectedStatus);
// Append "More"
list.add(moreStatus);
return list;
}
// --------------------------------------------------
// Custom ItemSelectedListener for ReservationStatusSpinner
// --------------------------------------------------
private class OnItemSelected implements OnItemSelectedListener {
private String mPreviousStatus;
private boolean mMoreClicked = false;
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String more = getContext().getResources().getString(R.string.status_more);
String status = getSelectedItem().toString();
ArrayList<String> items = new ArrayList<>();
if (status.equals(more)) {
items.addAll(getAllStatuses(getContext()));
items.remove(mMoreStatus);
setItems(items);
//setStatus(mPreviousStatus);
mMoreClicked = true;
// Reopen spinner (it closes after changing data) (TODO: Fix this)
ReservationStatusSpinner.this.performClick();
} else if (!mMoreClicked) {
filterAndSelect();
}
if (!status.equals(more)) {
if (mUserListener != null)
mUserListener.onItemSelected(parent, view, position, id);
if (mOnStatusSelectedListener != null)
mOnStatusSelectedListener.onStatusSelected(status);
}
mPreviousStatus = status;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
if (mUserListener != null)
mUserListener.onNothingSelected(parent);
}
}
}
在我的Spinner中,大部分工作都是在代码段末尾的public class ImageSpinnerAdapter extends ArrayAdapter<String> {
private LayoutInflater mInflater;
public ImageSpinnerAdapter(Context context, int textViewResourceId, List<String> titles) {
super(context, textViewResourceId, titles);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.row_image_spinner_dropdown, parent, false);
} else {
view = convertView;
}
ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon);
setIcon(icon, getItem(position));
TextView text = (TextView)view.findViewById(R.id.spinner_status_text);
text.setText(DataUtilities.addWhitespacesToStatus(getItem(position)));
view.setPadding(0, 0, 0, 0);
return view;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.row_image_spinner_view, parent, false);
} else {
view = convertView;
}
// Set icon
ImageView icon = (ImageView)view.findViewById(R.id.spinner_icon);
setIcon(icon, getItem(position));
view.setPadding(0, 0, 0, 0);
return view;
}
private void setIcon(ImageView icon, String status) {
// Make sure there are no whitespaces in status
status = DataUtilities.removeWhitespaceFromStatus(status);
// Get the correct image for each status
icon.setImageResource(DataUtilities.statusToIconResource(status));
}
}
完成的。
起初我认为问题是我的适配器上的转换视图(我最初没有使用转换视图模式),但正如您所看到的,我现在正在使用它。
问题出现在2个不同的设备和我的模拟器上,因此可以安全地假设它不是特定于设备的问题。
任何人有任何想法或任何指示?
答案 0 :(得分:1)
您必须使用MultiSelectListview和更多按钮创建自定义对话框。单击更多按钮,您必须将所有元素添加到Listview并调用notifyDataSetChanged()方法。
答案 1 :(得分:1)
默认Spinner无法简单地加载“更多”项。但“更多”按钮没有任何意义。如果你有30-50个项目,只需加载到Spinner。对于50-150项,使用自己的基于ListBox / RecyclerView的Spinner。如果超过150项用户太难搜索必要的一项。在最后一种情况下,添加“搜索”功能很有用。 有关提示,请参阅MultiSelect Spinner。