2017-02-22 171 views
0

我正在尝试为微调框实现“更多”按钮。基本上我只想先显示几个项目,当用户点击最后一个项目时(“更多...”),微调器将改变并显示所有项目。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个不同的设备和我的模拟器上,因此可以安全地假定它不是设备特定的问题。

任何人有任何想法或任何指针?

回答

1

您必须创建具有MultiSelectListview和更多按钮的自定义对话框。单击更多按钮,您必须将所有元素添加到Listview并调用notifyDataSetChanged()方法。

+0

因此,无法动态地添加/删除微调项目中的项目吗? – TheCrafter

+1

@TheCrafter - 对于添加/删除,您必须从arraylist中添加/删除并在itemSelected()方法上调用notifyDataSetChanged()。 – Ragini

+0

我已经这样做了。它确实更新了适配器数据集,但自动关闭了微调器。我正在寻找一种方法来做到这一点,而不关闭微调。 – TheCrafter

1

默认微调器不能简单地加载“更多”项目。但“更多”按钮没有意义。如果你有30-50项,只需将所有内容加载到Spinner。对于50-150项目,使用自己的ListBox/RecyclerView的微调器。如果超过150个项目用户太难搜索必要的一个项目。在最后一种情况下,可以添加“搜索”功能。 请参阅MultiSelect Spinner的想法。

enter image description here

+0

这对你来说可能没有意义,但对我的项目经理来说是非常有意义的。在研究其他选项之前,我仍在寻找一种使其与微调工作的方式。感谢您分享这个github项目! – TheCrafter

+0

@ TheCrafter,尽量为您的PM建议自己的解决方案 –

+0

任何方式MultiSelect Spinner良好的样品为自己的微调 –