2017-02-22 136 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良好的樣品爲自己的微調 –