2017-02-22 5 views
0

Ich versuche, ein „Mehr“ -Taste für einen Spinner zu implementieren. Grundsätzlich möchte ich zunächst nur ein paar Elemente anzeigen und wenn der Benutzer auf den letzten Eintrag ("Mehr ...") klickt, ändert sich der Spinner und zeigt alle Einträge an.Android: Ändern Spinner Artikel ohne Schließen der Spinner

Also die Funktion, die ich hier brauche, ist eine Möglichkeit, Spinner Artikel ohne zu ändern, den Spinner zu schließen. Ich habe alles bis auf den letzten Teil geschafft. Jedes Mal, wenn ich die Gegenstände ändere, wird der Spinner automatisch geschlossen (ohne den Fokus zu verlieren).

Die einzige Abhilfe, die ich dachte, war mSpinner.performClick() zu verwenden, sofort den Spinner zu öffnen, nachdem es geschlossen wird. Natürlich ist das nicht gut genug, weil ich diesen schnellen Close-Reopen-Effekt bekomme. Nicht cool.

ich eine benutzerdefinierte Spinner-Klasse erstellt, die die Logik verwaltet:

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); 
     } 
    } 
} 

und einen benutzerdefinierten Adapter:

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)); 
    } 
} 

In meinem Spinner, die meiste Arbeit in den private class OnItemSelected am Ende getan des Schnipsel.

Zuerst dachte ich, das Problem der Konvertit Blick auf meinem Adapter (ich war nicht das convert Ansicht Muster zunächst mit), aber wie man sehen kann ich es jetzt bin mit.

Das Problem tritt auf 2 verschiedenen Geräten und mein Emulator so, es ist sicher anzunehmen, dass es kein Gerät spezifisches Problem ist.

Wer irgendwelche Ideen oder irgendwelche Hinweise?

Antwort

1

Sie müssen ein benutzerdefiniertes Dialogfeld mit der Schaltfläche MultiSelectListview und More erstellen. Beim Klicken auf eine weitere Schaltfläche müssen Sie alle Elemente zu Listview hinzufügen und die notifyDataSetChanged() -Methode aufrufen.

+0

So gibt es keine Möglichkeit zum Hinzufügen/Löschen von Elementen aus einem dynamisch Spinnern? – TheCrafter

+1

@TheCrafter - Zum Hinzufügen/Löschen müssen Sie hinzufügen/entfernen von Arraylist und NotifyDataSetChanged() auf ItemSelected() -Methode aufrufen. – Ragini

+0

Das mache ich schon. Es aktualisiert zwar das Adapter-Dataset, schließt das Spinner jedoch automatisch. Ich suche nach einer Möglichkeit, dies zu tun, ohne den Spinner zu schließen. – TheCrafter

1

Standard Spinner kann nicht auf einfache Weise „Mehr“ Artikel zu laden. Aber "Mehr" hat keinen Sinn. Wenn Sie 30-50 Artikel haben, laden Sie einfach alle auf Spinner. Verwenden Sie für 50-150 Artikel einen eigenen ListBox/RecyclerView basierten Spinner. Wenn mehr 150 Elemente Benutzer zu schwer suchen, ein Element. Im letzten Fall ist es sinnvoll, die Suchfunktion hinzuzufügen. Siehe MultiSelect Spinner für Ideen.

enter image description here

+0

Es mag für Sie keinen Sinn ergeben, aber es macht für meinen Projektmanager Sinn. Ich suche immer noch nach einem Weg, um es mit einem Spinner arbeiten zu lassen, bevor ich andere Optionen untersuche. Vielen Dank für das Teilen dieses Github-Projekts! – TheCrafter

+0

@TheCrafter, versuchen Sie, eigene Lösung für Ihre PM vorschlagen –

+0

Jeder Weg MultiSelect Spinner gute Probe für eigene Spinner –