我正在尝试为微调框实现“更多”按钮。基本上我只想先显示几个项目,当用户点击最后一个项目时(“更多...”),微调器将改变并显示所有项目。Android:更改微调项目而不关闭微调框
因此,我需要的功能是一种动态更改微调项目而不需要关闭微调项目的方法。我已经设法做了一切,但最后一部分。每当我更改项目时,微调器自动关闭(不失焦点)。
我认为唯一的解决方法是使用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);
}
}
}
和一个自定义适配器:
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));
}
}
在我的微调,大部分工作是在private class OnItemSelected
末完成的片段。
起初我以为问题是我的适配器的转换视图(我起初没有使用转换视图模式),但你可以看到我现在正在使用它。
该问题出现在2个不同的设备和我的模拟器上,因此可以安全地假定它不是设备特定的问题。
任何人有任何想法或任何指针?
因此,无法动态地添加/删除微调项目中的项目吗? – TheCrafter
@TheCrafter - 对于添加/删除,您必须从arraylist中添加/删除并在itemSelected()方法上调用notifyDataSetChanged()。 – Ragini
我已经这样做了。它确实更新了适配器数据集,但自动关闭了微调器。我正在寻找一种方法来做到这一点,而不关闭微调。 – TheCrafter