Jak zrobić Android Spinner z początkowym tekstem „Wybierz jeden”?

569

Chcę użyć Spinnera, który początkowo (gdy użytkownik jeszcze nie dokonał wyboru) wyświetla tekst „Wybierz jeden”. Gdy użytkownik kliknie pokrętło, wyświetlona zostanie lista elementów, a użytkownik wybierze jedną z opcji. Po dokonaniu wyboru przez użytkownika wybrany element jest wyświetlany w pokrętle zamiast „Wybierz jeden”.

Mam następujący kod, aby utworzyć Błystkę:

String[] items = new String[] {"One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

Z tym kodem początkowo wyświetlany jest element „Jeden”. Mógłbym po prostu dodać nowy element „Wybierz jeden” do elementów, ale wtedy „Wybierz jeden” będzie również wyświetlany na liście rozwijanej jako pierwszy element, czego nie chcę.

Jak mogę rozwiązać ten problem?

Pieter Kuijpers
źródło
6
Idealne rozwiązanie leży w tym pytaniu: stackoverflow.com/questions/9863378/… Po prostu zastąp metodę getDropDownView ().
Sourab Sharma
Czy próbowałeś ustawić pierwszy element adaptera na „Wybierz jeden”?
IgorGanapolsky
[Oto inne świetne fajne rozwiązanie!] [1] [1]: stackoverflow.com/questions/9863378/...
AirtonCarneiro
wielorazowy spinner: github.com/henrychuangtw/ReuseSpinner
HenryChuang

Odpowiedzi:

255

Oto ogólne rozwiązanie, które przesłania Spinnerwidok. Zastępuje setAdapter()ustawienie pozycji początkowej na -1 i przekazuje SpinnerAdapterpodany parametr w celu wyświetlenia ciągu zachęty dla pozycji mniejszej niż 0.

Zostało to przetestowane na Androidzie od 1.5 do 4.2, ale kupujący uważaj! Ponieważ to rozwiązanie opiera się na refleksji, aby wywołać funkcję prywatną, AdapterView.setNextSelectedPositionInt()i AdapterView.setSelectedPositionInt()nie ma gwarancji, że będzie działać w przyszłych aktualizacjach systemu operacyjnego. Wydaje się prawdopodobne, że tak będzie, ale nie jest to w żaden sposób gwarantowane.

Zwykle nie tolerowałbym czegoś takiego, ale zadawano to pytanie wystarczająco dużo razy i wydaje się to rozsądną prośbą, że myślałem, że opublikuję moje rozwiązanie.

/**
 * A modified Spinner that doesn't automatically select the first entry in the list.
 *
 * Shows the prompt if nothing is selected.
 *
 * Limitations: does not display prompt if the entry list is empty.
 */
public class NoDefaultSpinner extends Spinner {

    public NoDefaultSpinner(Context context) {
        super(context);
    }

    public NoDefaultSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(SpinnerAdapter orig ) {
        final SpinnerAdapter adapter = newProxy(orig);

        super.setAdapter(adapter);

        try {
            final Method m = AdapterView.class.getDeclaredMethod(
                               "setNextSelectedPositionInt",int.class);
            m.setAccessible(true);
            m.invoke(this,-1);

            final Method n = AdapterView.class.getDeclaredMethod(
                               "setSelectedPositionInt",int.class);
            n.setAccessible(true);
            n.invoke(this,-1);
        } 
        catch( Exception e ) {
            throw new RuntimeException(e);
        }
    }

    protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
        return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
                obj.getClass().getClassLoader(),
                new Class[]{SpinnerAdapter.class},
                new SpinnerAdapterProxy(obj));
    }



    /**
     * Intercepts getView() to display the prompt if position < 0
     */
    protected class SpinnerAdapterProxy implements InvocationHandler {

        protected SpinnerAdapter obj;
        protected Method getView;


        protected SpinnerAdapterProxy(SpinnerAdapter obj) {
            this.obj = obj;
            try {
                this.getView = SpinnerAdapter.class.getMethod(
                                 "getView",int.class,View.class,ViewGroup.class);
            } 
            catch( Exception e ) {
                throw new RuntimeException(e);
            }
        }

        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
            try {
                return m.equals(getView) && 
                       (Integer)(args[0])<0 ? 
                         getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) : 
                         m.invoke(obj, args);
            } 
            catch (InvocationTargetException e) {
                throw e.getTargetException();
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        protected View getView(int position, View convertView, ViewGroup parent) 
          throws IllegalAccessException {

            if( position<0 ) {
                final TextView v = 
                  (TextView) ((LayoutInflater)getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE)).inflate(
                      android.R.layout.simple_spinner_item,parent,false);
                v.setText(getPrompt());
                return v;
            }
            return obj.getView(position,convertView,parent);
        }
    }
}
emmby
źródło
7
@emmby Czy masz pomysł, jak wyczyścić zaznaczenie po ustawieniu go przez użytkownika? Próbowałem refaktoryzować dwa wywołania invoke () do metody clearSelection (), ale tak naprawdę to nie działa. Chociaż wyskakująca lista pokazuje poprzednio wybrany element jako niewybrany, widżet przędzarki nadal pokazuje go jako wybrany, a jeśli użytkownik ponownie wybierze ten sam element, funkcja onItemSelected () nie jest wywoływana.
Qwertie,
3
czy niektórzy mogliby wyjaśnić, jak korzystać z klasy wyższej?
Bishan,
4
To rozwiązanie nie jest w 100% idealne na Androidzie 4.2 (Cyanogenmod 10.1), używając Androida: wpisy. Wysokość zawyżonego TextView jest mniejsza niż wysokość dowolnego zasobu, który napełni domyślny adapter. Tak więc, kiedy faktycznie wybierzesz opcję, wysokość wzrasta, ~ 10px w moim Galaxy S, co jest nie do przyjęcia. Wypróbowałem kilka rzeczy (grawitacja, wypełnienie, margines itp.) I żadna nie działała niezawodnie na różnych urządzeniach, więc wybiorę inne rozwiązanie.
Ligi
3
@DavidDoria Musisz użyć klasy NoDefaultSpinner w pliku układu. Skopiuj źródło z góry do swojego projektu, np. Do pakietu com.example.customviews. Teraz w twoim układzie xml zamiast <Spinner ...> użyj <com.example.customviews.NoDefaultSpinner ...> Reszta kodu może pozostać taka sama. Nie zapomnij dodać atrybutu android: prompt do widoku <com.example.customviews.NoDefaultSpinner> w swoim układzie.
Ridcully
2
@emmby spinnerBrand.setSelection (-1); nie działa
Sachin C
291

Co możesz zrobić, to udekorować swój SpinnerAdapter pomocą tego, który przedstawia widok „Wybierz opcję ...” na początku, aby wyświetlał Spinner bez niczego zaznaczonego.

Oto działający przykład przetestowany dla Androida 2.3 i 4.0 (nie używa niczego w bibliotece kompatybilności, więc powinno być na chwilę w porządku) Ponieważ jest dekoratorem, powinien być łatwy do ponownego zainstalowania istniejącego kodu i działa dobrze CursorLoaderrównież z s. (Zamień kursor na cursorAdapteroczywiście zawinięty ...)

Istnieje błąd Androida, który sprawia, że ​​nieco trudniej jest ponownie używać widoków. (Więc musisz użyć setTaglub czegoś innego, aby upewnić się, że masz convertViewrację.) Spinner nie obsługuje wielu typów widoków

Uwagi do kodu: 2 konstruktory

Pozwala to na użycie standardowego monitu lub zdefiniowanie własnego „niczego nie wybranego” jako pierwszego wiersza lub obu tych elementów lub żadnego. (Uwaga: niektóre motywy pokazują DropDown dla Spinnera zamiast okna dialogowego. Lista rozwijana zwykle nie wyświetla monitu)

Definiujesz układ, aby wyglądał jak monit, na przykład wyszarzony ...

Początkowe nic nie wybrane

Za pomocą standardowego monitu (zauważ, że nic nie jest zaznaczone):

Ze standardowym monitem

Lub z podpowiedzią i czymś dynamicznym (mógł nie mieć również podpowiedzi):

Monituj i nic nie zaznaczono wiersza

Zastosowanie w powyższym przykładzie

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setPrompt("Select your favorite Planet!");

spinner.setAdapter(
      new NothingSelectedSpinnerAdapter(
            adapter,
            R.layout.contact_spinner_row_nothing_selected,
            // R.layout.contact_spinner_nothing_selected_dropdown, // Optional
            this));

contact_spinner_row_nothing_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textSize="18sp"
    android:textColor="#808080"
    android:text="[Select a Planet...]" />

NothingSelectedSpinnerAdapter.java

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;

/**
 * Decorator Adapter to allow a Spinner to show a 'Nothing Selected...' initially
 * displayed instead of the first choice in the Adapter.
 */
public class NothingSelectedSpinnerAdapter implements SpinnerAdapter, ListAdapter {

    protected static final int EXTRA = 1;
    protected SpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    /**
     * Use this constructor to have NO 'Select One...' item, instead use
     * the standard prompt or nothing at all.
     * @param spinnerAdapter wrapped Adapter.
     * @param nothingSelectedLayout layout for nothing selected, perhaps
     * you want text grayed out like a prompt...
     * @param context
     */
    public NothingSelectedSpinnerAdapter(
      SpinnerAdapter spinnerAdapter,
      int nothingSelectedLayout, Context context) {

        this(spinnerAdapter, nothingSelectedLayout, -1, context);
    }

    /**
     * Use this constructor to Define your 'Select One...' layout as the first
     * row in the returned choices.
     * If you do this, you probably don't want a prompt on your spinner or it'll
     * have two 'Select' rows.
     * @param spinnerAdapter wrapped Adapter. Should probably return false for isEnabled(0)
     * @param nothingSelectedLayout layout for nothing selected, perhaps you want
     * text grayed out like a prompt...
     * @param nothingSelectedDropdownLayout layout for your 'Select an Item...' in
     * the dropdown.
     * @param context
     */
    public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
            int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context) {
        this.adapter = spinnerAdapter;
        this.context = context;
        this.nothingSelectedLayout = nothingSelectedLayout;
        this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public final View getView(int position, View convertView, ViewGroup parent) {
        // This provides the View for the Selected Item in the Spinner, not
        // the dropdown (unless dropdownView is not set).
        if (position == 0) {
            return getNothingSelectedView(parent);
        }
        return adapter.getView(position - EXTRA, null, parent); // Could re-use
                                                 // the convertView if possible.
    }

    /**
     * View to show in Spinner with Nothing Selected
     * Override this to do something dynamic... e.g. "37 Options Found"
     * @param parent
     * @return
     */
    protected View getNothingSelectedView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedLayout, parent, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
        // Spinner does not support multiple view types
        if (position == 0) {
            return nothingSelectedDropdownLayout == -1 ?
              new View(context) :
              getNothingSelectedDropdownView(parent);
        }

        // Could re-use the convertView if possible, use setTag...
        return adapter.getDropDownView(position - EXTRA, null, parent);
    }

    /**
     * Override this to do something dynamic... For example, "Pick your favorite
     * of these 37".
     * @param parent
     * @return
     */
    protected View getNothingSelectedDropdownView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedDropdownLayout, parent, false);
    }

    @Override
    public int getCount() {
        int count = adapter.getCount();
        return count == 0 ? 0 : count + EXTRA;
    }

    @Override
    public Object getItem(int position) {
        return position == 0 ? null : adapter.getItem(position - EXTRA);
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public long getItemId(int position) {
        return position >= EXTRA ? adapter.getItemId(position - EXTRA) : position - EXTRA;
    }

    @Override
    public boolean hasStableIds() {
        return adapter.hasStableIds();
    }

    @Override
    public boolean isEmpty() {
        return adapter.isEmpty();
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        adapter.registerDataSetObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        adapter.unregisterDataSetObserver(observer);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(int position) {
        return position != 0; // Don't allow the 'nothing selected'
                                             // item to be picked.
    }

}
aaronvargas
źródło
52
To eleganckie rozwiązanie problemu. Kod działa dokładnie tak samo, jak kopiowanie i wklejanie do mojego projektu. +1 za brak refleksji.
Richard Le Mesurier
2
To świetne rozwiązanie. Jeśli ktoś chce wiedzieć, jak zastąpić tytuł, nie tylko przed wybraniem elementu, ale przez cały czas w wywołaniu getView (), po prostu zwróć getNothingSelectedView (lub dowolny inny niestandardowy widok) przez cały czas. Lista rozwijana nadal będzie wypełniona elementami z adaptera, ale możesz teraz kontrolować tytuł PO wybraniu czegoś.
OldSchool4664
6
To naprawdę eleganckie rozwiązanie problemu, który nie powinien istnieć (wypróbuj programowanie na iPhone'a). Świetnie i dziękuję! Cieszę się, że ktoś zapamiętał wzory itp.
użytkownik1700737
3
@prashantwosti, kod został zaktualizowany do pracy z Lollipop. W szczególności getItemViewType () i getViewTypeCount ().
aaronvargas
3
@aaronvargas po wybraniu przedmiotu z tarczy czy mogę cofnąć i wybrać „[Wybierz planetę” ”?
modabeckham
130

Skończyło się na tym Buttonzamiast. Podczas gdy a Buttonnie jestSpinner , zachowanie można łatwo dostosować.

Najpierw utwórz adapter jak zwykle:

String[] items = new String[] {"One", "Two", "Three"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_spinner_dropdown_item, items);

Zauważ, że używam simple_spinner_dropdown_itemjako identyfikatora układu. Pomoże to stworzyć lepszy wygląd podczas tworzenia okna dialogowego alertu.

W module obsługi onClick dla mojego przycisku mam:

public void onClick(View w) {
  new AlertDialog.Builder(this)
  .setTitle("the prompt")
  .setAdapter(adapter, new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

      // TODO: user specific action

      dialog.dismiss();
    }
  }).create().show();
}

I to wszystko!

HRJ
źródło
10
Zgadzam się z tą odpowiedzią. Poza tym przycisk jest znacznie łatwiejszy do stylizacji niż Spinner.
Romain Piel
@HRJ Wdrożyłem sposób, w jaki zasugerowałeś, ale wybrany wcześniej element nie jest podświetlany (oznacza, że ​​przycisk opcji musi być wyróżniony zieloną kropką pośrodku) .... Jak to osiągnąć w metodzie OnClick () przycisk. Proszę o pomoc HRJ .....
Avadhani Y
2
Przycisk z tym układem, który jest idealny <Przycisk android: id = "@ + id / miasto" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_margin = "5dp" android: gravity = "left" android: background = "@ android: drawable / btn_dropdown" android: text = "@ string / city_prompt" />
kml_ckr 12.01.14
Jak w takim razie zaktualizowałbyś tekst przycisku, aby odzwierciedlić wybór, tak jak by to było w przypadku pokrętła?
shim
3
rozwiązanie problemu: po prostu zamiast SetAdapter użyj SetSingleChoiceItems
Grzegorz Dev
67

Po pierwsze, możesz być zainteresowany promptatrybutem Spinnerklasy. Zobacz poniższy obrazek: „Wybierz planetę” to monit, który można ustawić w pliku XML za pomocą android:prompt="" .

wprowadź opis zdjęcia tutaj

Chciałem zaproponować podklasę Spinner, w której można wewnętrznie utrzymywać dwa adaptery. Jeden adapter z opcją „Wybierz jeden”, a drugi prawdziwy adapter (z rzeczywistymi opcjami), a następnie za pomocą przycisku OnClickListenerprzełączaj adaptery przed wyświetleniem okna dialogowego opcji. Jednak po wypróbowaniu tego pomysłu doszedłem do wniosku, że nie można odbierać OnClickzdarzeń dla samego widżetu.

Możesz owinąć pokrętło w innym widoku, przechwycić kliknięcia w widoku, a następnie poprosić CustomSpinnero zmianę adaptera, ale wydaje się to okropnym włamaniem.

Czy naprawdę musisz pokazać „Wybierz jeden”?

Casey
źródło
36
Nie chodzi tylko o konieczność pokazania „Wybierz jeden”, ale dotyczy również przypadku, w którym wartość pokrętła może opcjonalnie pozostać pusta.
greg7gkb
5
także, z tą opcją, Ziemia jest wyświetlana jako wybór w Błystce, zanim cokolwiek zostanie wybrane, w mojej aplikacji wolałbym, aby użytkownik mógł powiedzieć, że jeszcze niczego nie wybrał
Dylan Murphy
2
to naprawdę nie odpowiada na pytanie. ludzie szukają sposobu, aby sam spinner domyślnie pokazywał „Wybierz jeden” zamiast pierwszego elementu na liście planet, w tym przykładzie
JMRboosties
58

Ten kod został przetestowany i działa na Androidzie 4.4

wprowadź opis zdjęcia tutaj

Spinner spinner = (Spinner) activity.findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_spinner_dropdown_item) {

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {

                View v = super.getView(position, convertView, parent);
                if (position == getCount()) {
                    ((TextView)v.findViewById(android.R.id.text1)).setText("");
                    ((TextView)v.findViewById(android.R.id.text1)).setHint(getItem(getCount())); //"Hint to be displayed"
                }

                return v;
            }       

            @Override
            public int getCount() {
                return super.getCount()-1; // you dont display last item. It is used as hint.
            }

        };

        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        adapter.add("Daily");
        adapter.add("Two Days");
        adapter.add("Weekly");
        adapter.add("Monthly");
        adapter.add("Three Months");
        adapter.add("HINT_TEXT_HERE"); //This is the text that will be displayed as hint.


        spinner.setAdapter(adapter);
        spinner.setSelection(adapter.getCount()); //set the hint the default selection so it appears on launch.
        spinner.setOnItemSelectedListener(this);
Manos
źródło
getItem(getCount())jest dla mnie podkreślony na czerwono? Nie można rozwiązać metody setHint
Zapnologica
Mam wątpliwości, widziałem wiele rozwiązań w tym wątku .. ale dlaczego wszyscy dodają wskazówkę do ostatniego. Czy dodawanie podpowiedzi w pierwszym rzędzie jest błędne?
akashPatra
Nie mogę ustawić „setOnItemSelectedListener (this);” ponieważ używam 'implementuje NavigationView.OnNavigationItemSelectedListener', czy mogę usunąć 'setOnItemSelectedListener (this);' bez żadnych problemów?
CGR
@akashpatra Powodem dodania podpowiedzi jest to, że ArrayAdapter for spinner może pobierać swoje wartości z różnych źródeł w czasie wykonywania.
VinKrish,
to naprawdę mi pomogło
sunil
31

Znalazłem to rozwiązanie:

String[] items = new String[] {"Select One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
        items[0] = "One";
        selectedItem = items[position];
    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
    }
});

Wystarczy zmienić tablicę [0] za pomocą „Select One”, a następnie w onItemSelected zmienić nazwę na „One”.

Nie jest to klasyczne rozwiązanie, ale działa: D

Marco da Gualdo
źródło
5
To mi nie zadziałało. Po wybraniu elementu „Jeden” nadal pojawia się komunikat „Wybierz jeden”.
Leo Landau,
To nie zadziała, ponieważ interfejs onItemSelected będzie zawsze wywoływał po raz pierwszy.
Vaibhav Kadam
20

Brak domyślnego interfejsu API do ustawiania podpowiedzi w programie Spinner. Aby go dodać, potrzebujemy małego obejścia bez implementacji refleksji bezpieczeństwa

List<Object> objects = new ArrayList<Object>();
objects.add(firstItem);
objects.add(secondItem);
// add hint as last item
objects.add(hint);

HintAdapter adapter = new HintAdapter(context, objects, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

Spinner spinnerFilmType = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);

// show hint
spinner.setSelection(adapter.getCount());

Źródło adaptera:

public class HintAdapter
        extends ArrayAdapter<Objects> {

    public HintAdapter(Context theContext, List<Object> objects) {
        super(theContext, android.R.id.text1, android.R.id.text1, objects);
    }

    public HintAdapter(Context theContext, List<Object> objects, int theLayoutResId) {
        super(theContext, theLayoutResId, android.R.id.text1, objects);
    }

    @Override
    public int getCount() {
        // don't display last item. It is used as hint.
        int count = super.getCount();
        return count > 0 ? count - 1 : count;
    }
}

Pierwotnym źródłem

Jakow Mospan
źródło
co to jest tekst R.id.1? czy to jakiś układ lub widok? proszę
opracuj
Powinno byćandroid.R.id.text1
Jakow Mospan
Mam wątpliwości, widziałem wiele rozwiązań w tym wątku .. ale dlaczego wszyscy dodają wskazówkę do ostatniego. Czy dodawanie podpowiedzi w pierwszym rzędzie jest błędne?
akashPatra
@akashpatra Nie pamiętam dokładnie, ale wydaje mi się, że był jakiś problem, kiedy próbowałem zrobić to jako pierwszą listę przedmiotów. W każdym razie zawsze możesz spróbować i skomentować tutaj, cała magia jest wokół getCountmetody
Yakiv Mospan
@YakivMospan Otrzymuję NPE, gdy go używam, prawdopodobnie z powodu Reflection podczas korzystania z ProGuard. Czy wiesz jak to naprawić?
Alan
17

Tutaj jest wiele odpowiedzi, ale jestem zaskoczony, że nikt nie zaproponował prostego rozwiązania: umieść TextView na urządzeniu Spinner. Ustaw detektor kliknięć w TextView, który ukrywa TextView pokazuje Spinner i wywołuje spinner.performClick ().

mjancola
źródło
9

Mam ten sam problem z przędzarką, z pustym wyborem i znalazłem lepsze rozwiązanie. Spójrz na ten prosty kod.

Spinner lCreditOrDebit = (Spinner)lCardPayView.findViewById(R.id.CARD_TYPE);
spinneradapter lAdapter = 
  new spinneradapter(
    BillPayScreen.this, 
    ndroid.R.layout.simple_spinner_item,getResources().getStringArray(R.array.creditordebit));
lAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
lCreditOrDebit.setAdapter(lAdapter);

Tutaj spinneradapter jest małym dostosowaniem do arrayadapter. To wygląda tak:

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class spinneradapter extends ArrayAdapter<String>{
    private Context m_cContext;
    public spinneradapter(Context context,int textViewResourceId, String[] objects) {
        super(context, textViewResourceId, objects);
        this.m_cContext = context;
    }

    boolean firsttime = true;
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(firsttime){
            firsttime = false;
            //Just return some empty view
            return new ImageView(m_cContext);
        }
        //Let the array adapter take care of it this time.
        return super.getView(position, convertView, parent);
    }
}
Rajasekhar
źródło
6
Problem z tym podejściem polega na tym, że gdy pojawia się lista, nadal wybiera pierwszy element na liście. Ponieważ jest to już zaznaczone, nie można go dotknąć, aby wybrać - działa tak, jakby nie wybrano żadnego.
jwadsack
7

Możesz zmienić go na widok tekstu i użyć tego:

android:style="@android:style/Widget.DeviceDefault.Light.Spinner"

a następnie zdefiniuj android:textwłaściwość.

Christian Vielma
źródło
Działa tylko dla API 14 i nowszych.
Giulio Piancastelli,
6

Plik XML:

<Spinner android:id="@+id/locationSpinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/select_location" />

Czynność:

private Spinner featuresSelection;
private ArrayAdapter<CharSequence> featuresAdapter;
private List<CharSequence> featuresList;

onCreate:

featuresList = new ArrayList<CharSequence>();
featuresAdapter = new ArrayAdapter<CharSequence>(this,
  android.R.layout.simple_spinner_item, featuresList);
featuresAdapter.setDropDownViewResource(
  android.R.layout.simple_spinner_dropdown_item);
featuresSelection = ((Spinner) yourActivity.this
  .findViewById(R.id.locationSpinner));
featuresSelection.setAdapter(featuresAdapter);
featuresSelection.setOnItemSelectedListener(
  new MyOnItemSelectedListener());

Niektóre funkcje (programowo dodawaj elementy do adaptera)>

featuresAdapter.add("some string");

Teraz masz pustą przędzarkę i możesz pisać kod, aby nie otwierać okna dialogowego, jeśli jest puste. Lub mogą cofnąć. Ale wypełniasz ją również funkcją lub inną listą w czasie wykonywania.

trgraglia
źródło
Nie ma też potrzeby powiadomieniaDataSetChanged (), ponieważ domyślnie powinno być ustawione na true.
trgraglia,
4

Próbowałem następująco. Weź przycisk i nadaj mu zdarzenie click. Zmieniając tło przycisku, wydaje się być pokrętłem.

Deklaruj jako globalne zmienne alertdialog i wartość domyślną.

AlertDialog d;
static int default_value = 0;
final Button btn = (Button) findViewById(R.id.button1);
btn .setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v)
{
    //c.show();
    final CharSequence str[] = {"Android","Black Berry","Iphone"};
        AlertDialog.Builder builder =
          new AlertDialog.Builder(TestGalleryActivity.this).setSingleChoiceItems(
            str, default_value,new  DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int position)
            {
                Toast.makeText(TestGalleryActivity.this,
                               "" + position,
                               Toast.LENGTH_SHORT).show();
                default_value = position;
                btn.setText(str[position]);
                if(d.isShowing())
                    d.dismiss();
            }
        }).setTitle("Select Any");
        d = builder.create();
        d.show();
    }
});
Ramesh Akula
źródło
4

To jest mój sposób:

List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
 @Override
public int getCount() {
    return(listsize); // Truncate the list
}
};
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

mySpinner.setSelection(listsize); // Hidden item to appear in the spinner
Cabezas
źródło
to otwiera
pokrętło
3

Rzuć okiem na iosched app, która stanowi rozwiązanie ogólnego zastosowania polegające na dodawaniu elementu na początek listy. W szczególności, jeśli używasz CursorAdapter, spójrz na TracksAdapter.java który rozszerza tę definicję, aby zapewnić metodę „setHasAllItem” i powiązany kod do zarządzania liczbą list, aby poradzić sobie z dodatkową pozycją na górze.

Za pomocą niestandardowego adaptera możesz ustawić tekst na „Wybierz jeden” lub cokolwiek innego, co chcesz powiedzieć o tym górnym elemencie.

Sport
źródło
3

Mam plik spinner na moim pliku main.xml, którego identyfikator to @+id/spinner1

oto co piszę w mojej funkcji OnCreate:

spinner1 = (Spinner)this.findViewById(R.id.spinner1);
final String[] groupes = new String[] {"A", "B", "C", "D", "E", "F", "G", "H"};
ArrayAdapter<CharSequence> featuresAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, new ArrayList<CharSequence>());
featuresAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(featuresAdapter);
for (String s : groupes) featuresAdapter.add(s);

spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
     public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
         // Here go your instructions when the user chose something
         Toast.makeText(getBaseContext(), groupes[position], 0).show();
     }
     public void onNothingSelected(AdapterView<?> arg0) { }
});

Nie wymaga żadnej implementacji w klasie.

Cyryl
źródło
3

Znalazłem wiele dobrych rozwiązań w tym zakresie. większość działa, dodając element na końcu adaptera i nie wyświetlając ostatniego elementu na liście rozwijanej. Dużym problemem dla mnie było to, że rozwijana lista spinnerów zacznie się od dołu listy. Tak więc użytkownik widzi ostatnie przedmioty zamiast pierwszych (w przypadku wielu przedmiotów do pokazania), po pierwszym dotknięciu pokrętła.

Więc umieszczam wskazówkę na początku listy. i ukryj pierwszy element na liście rozwijanej.

private void loadSpinner(){

    HintArrayAdapter hintAdapter = new HintArrayAdapter<String>(context, 0);

    hintAdapter.add("Hint to be displayed");
    hintAdapter.add("Item 1");
    hintAdapter.add("Item 2");
            .
            .
    hintAdapter.add("Item 30");

    spinner1.setAdapter(hintAdapter);

    //spinner1.setSelection(0); //display hint. Actually you can ignore it, because the default is already 0
    //spinner1.setSelection(0, false); //use this if don't want to onItemClick called for the hint

    spinner1.setOnItemSelectedListener(yourListener);
}

private class HintArrayAdapter<T> extends ArrayAdapter<T> {

    Context mContext;

    public HintArrayAdapter(Context context, int resource) {
        super(context, resource);
        this.mContext = context
    }

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
        TextView texview = (TextView) view.findViewById(android.R.id.text1);

        if(position == 0) {
            texview.setText("");
            texview.setHint(getItem(position).toString()); //"Hint to be displayed"
        } else {
            texview.setText(getItem(position).toString());
        }

        return view;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view;

        if(position == 0){
            view = inflater.inflate(R.layout.spinner_hint_list_item_layout, parent, false); // Hide first row
        } else {
            view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, parent, false);
            TextView texview = (TextView) view.findViewById(android.R.id.text1);
            texview.setText(getItem(position).toString());
        } 

        return view;
    }
}

ustaw poniższy układ w @Override getDropDownView (), gdy pozycja wynosi 0, aby ukryć pierwszy wiersz podpowiedzi.

R.layout.spinner_hint_list_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

</LinearLayout>
Alireza Sobhani
źródło
3

Ponadto istnieje prosta sztuczka, aby wyświetlić domyślne:

Możesz dodać wartość domyślną do listy, a następnie dodać całą swoją kolekcję za pomocą list.addAll(yourCollection);

Przykładowy działający kod tutaj:

List<FuelName> fuelList = new ArrayList<FuelName>();
                    fuelList.add(new FuelName(0,"Select One"));
                    fuelList.addAll(response.body());
                    ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, fuelList);
                    //fuelName.setPrompt("Select Fuel");
                    fuelName.setAdapter(adapter);

Mam nadzieję, że odzyskasz swoją złożoność. Miłego kodowania!

Majedur Rahaman
źródło
2

Myślę, że najłatwiejszym sposobem jest utworzenie fikcyjnego elementu w indeksie 0, mówiąc „wybierz jeden”, a następnie zapisując, może sprawdź, czy wybór nie jest równy 0.

Tobiasz
źródło
4
Co z przeglądaniem listy przedmiotów? Chcesz zobaczyć pozycję „wybierz jedną” u góry? Nie chodzi tylko o oszczędzanie.
Krzysztof Wolny
@KrzysztofWolny Spinner domyślnie wyświetla pozycję na pozycji 0
rds
2

To jest mój ostatni przykład „wszystko w” dla pokrętła

W Activity_my_form.xml

    <Button
        android:id="@+id/btnSpinnerPlanets"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="left|center_vertical"
        android:singleLine="true"
        android:text="@string/selectAPlanet"
        android:textSize="10sp"
        android:background="@android:drawable/btn_dropdown">
    </Button>

W strings.xml

<string name="selectAPlanet">Select planet&#8230;</string>

<string-array name="planets__entries">
    <item>The Sun with a name very long so long long long long longThe Sun with a name very long so long long long long longThe Sun with a name very long so long long long long long</item>
    <item>Mercury</item>
    <item>Venus</item>
    <item>Earth</item>
    <item>Mars</item>
    <item>Jupiter</item>
    <item>Saturn</item>
    <item>Uranus</item>
    <item>Neptune</item>
</string-array>

W MyFormActivity.java

public class MyFormActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ((Button) findViewById(R.id.btnSpinnerPlanets)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String[] items = view.getResources().getStringArray(R.array.planets__entries);
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(MyFormActivity.this, android.R.layout.simple_spinner_dropdown_item, items);
                new AlertDialog.Builder(MyFormActivity.this).setTitle("the prompt").setAdapter(adapter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((Button) findViewById(R.id.btnSpinnerPlanets)).setText(items[which]);
                        dialog.dismiss();
                    }
                }).create().show();
            }
        });     

    }

}   

W końcu otrzymałem konfigurowalny rozmiar czcionki, nie można wybierać pierwszego elementu pokrętła !!! Dzięki HRJ

wildnove
źródło
1

Rozszerzając SpinnerAdapter, zastępujesz Viewmetody dwuprodukcyjne getView(int, View, ViewGroup)i getDropDownView(int, View, ViewGroup). Pierwszy zasila Viewwstawiony w Spinnersiebie; drugi zawiera Viewlistę rozwijaną (jak sama nazwa wskazuje). Możesz zastąpić to, getView(...)aby do momentu wybrania elementu wyświetlał TextViewmonit zawierający; następnie, gdy wykryjesz, że element został wybrany, zmieniasz go, aby wyświetlać TextViewodpowiadający temu element .

public class PromptingAdapter extends SpinnerAdapter {

    //... various code ...

    private boolean selectionmade = false;

    //call this method from the OnItemSelectedListener for your Spinner
    public setSelectionState(boolean b) {
        selectionmade = b;
    }

    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(selectionmade) {
            //your existing code to supply a View for the Spinner
            //you could even put "return getDropDownView(position, recycle, container);"
        }
        else {
            View output;
            if(recycle instanceof TextView) {
                 output = recycle;
            }
            else {
                 output = new TextView();
                 //and layout stuff
            }
            output.setText(R.string.please_select_one);
            //put a string "please_select_one" in res/values/strings.xml
            return output;
        }
    }

//...
}
Andrew Wyld
źródło
1
Odkryłem wadę tej metody: Prządka automatycznie wybiera przedmiot natychmiast. Zaraz to znajdę.
Andrew Wyld
Mówiłem za wcześnie. Nie poddałem się jednak. Zauważ, że zgodnie z Spinnersamouczkiem (który rzekomo wyświetla ToastPO, gdy wybrałeś element) ten OUGHT do pracy: developer.android.com/resources/tutorials/views/…
Andrew Wyld
1

Dla tych, którzy używają Xamarin, tutaj jest C # odpowiednik powyższej odpowiedzi aaronvargas.

using Android.Content;
using Android.Database;
using Android.Views;
using Android.Widget;
using Java.Lang;

namespace MyNamespace.Droid
{ 
  public class NothingSelectedSpinnerAdapter : BaseAdapter, ISpinnerAdapter, IListAdapter
  {
    protected static readonly int EXTRA = 1;
    protected ISpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, Context context) : this(spinnerAdapter, nothingSelectedLayout, -1, context)
    {
    }

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context)
    {
      this.adapter = spinnerAdapter;
      this.context = context;
      this.nothingSelectedLayout = nothingSelectedLayout;
      this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
      layoutInflater = LayoutInflater.From(context);
    }

    protected View GetNothingSelectedView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedLayout, parent, false);
    }

    protected View GetNothingSelectedDropdownView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedDropdownLayout, parent, false);
    }

    public override Object GetItem(int position)
    {
      return position == 0 ? null : adapter.GetItem(position - EXTRA);
    }

    public override long GetItemId(int position)
    {
      return position >= EXTRA ? adapter.GetItemId(position - EXTRA) : position - EXTRA;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
      // This provides the View for the Selected Item in the Spinner, not
      // the dropdown (unless dropdownView is not set).
      if (position == 0)
      {
        return GetNothingSelectedView(parent);
      }

      // Could re-use the convertView if possible.
      return this.adapter.GetView(position - EXTRA, null, parent);
    }

    public override int Count
    {
      get
      {
        int count = this.adapter.Count;
        return count == 0 ? 0 : count + EXTRA;
      }
    }

    public override View GetDropDownView(int position, View convertView, ViewGroup parent)
    {
      // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
      // Spinner does not support multiple view types
      if (position == 0)
      {
        return nothingSelectedDropdownLayout == -1 ?
          new View(context) :
          GetNothingSelectedDropdownView(parent);
      }

      // Could re-use the convertView if possible, use setTag...
      return adapter.GetDropDownView(position - EXTRA, null, parent);
    }

    public override int GetItemViewType(int position)
    {
      return 0;
    }

    public override int ViewTypeCount => 1;

    public override bool HasStableIds => this.adapter.HasStableIds;

    public override bool IsEmpty => this.adapter.IsEmpty;

    public override void RegisterDataSetObserver(DataSetObserver observer)
    {
      adapter.RegisterDataSetObserver(observer);
    }

    public override void UnregisterDataSetObserver(DataSetObserver observer)
    {
      adapter.UnregisterDataSetObserver(observer);
    }

    public override bool AreAllItemsEnabled()
    {
      return false;
    }

    public override bool IsEnabled(int position)
    {
      return position > 0;
    }
  }
}
MPavlak
źródło
1

Rozwiązałem również ten problem, używając następującego kodu. Załóżmy, że masz listę przedmiotów, np

ArrayList<Item> itemsArrayList = new ArrayList<Item>();
Item item1 = new Item();
item1.setId(1);
item1.setData("First Element");
Item item2 = new Item();
item2.setId(2);
Item2.setData("Second Element");
itemsArrayList.add(item1);
itemsArrayList.add(item2);

Teraz musimy dostarczyć struny do przędzarki, ponieważ przędzarka nie może zrozumieć obiektu. Stworzymy więc nową listę tablic z takimi ciągami znaków jak ta ->

ArrayList<String> itemStringArrayList = new ArrayList<String>();
for(Item item : itemsArrayList) {
    itemStringArrayList.add(item.getData());
}

Teraz mamy itemStringArrayListlistę tablic z dwoma elementami łańcucha. I musimy pokazać tekst „Wybierz element” jako pierwszy element. Więc musimy wstawić nowy ciąg do itemStringArrayList.

itemStringArrayList.add("Select Item");

Teraz mamy listę tablic itemsArrayListi chcemy pokazać dwa elementy w menu rozwijanym. Ale warunkiem jest tutaj ... Jeśli niczego nie wybieramy, to wtedySelect Item powinien pojawić się jako pierwszy element, który nie zostanie włączony.

Możemy więc zaimplementować tę funkcjonalność w ten sposób. Jeśli musisz załadować elementy listy tablic do tarczy Android. Będziesz musiał użyć adaptera. Więc tutaj użyję ArrayAdapter. Możemy również użyć dostosowanego adaptera.

ArrayAdapter<String> itemsArrayAdapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.spinner_item, itemsArrayList){
        @Override
        public boolean isEnabled(int position) {
            if(position == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        @Override
        public View getDropDownView(int position, View convertView,
                                    ViewGroup parent) {
            View view = super.getDropDownView(position, convertView, parent);
            TextView tv = (TextView) view;
            if(position == 0){
                // Set the hint text color gray
                tv.setTextColor(Color.GRAY);
            }
            else {
                tv.setTextColor(Color.BLACK);
            }
            return view;
        }
    };

itemsArrayAdapter.setDropDownViewResource(R.layout.spinner_item);
your_spinner_name.setAdapter(itemsArrayAdapter);

Tutaj w tym kodzie. korzystamy z niestandardowego układu tarczy, tj R.layout.spinner_item. To prosty widok tekstu

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:textStyle="italic"
    android:fontFamily="sans-serif-medium"
    />

Musimy wyłączyć pierwszy tekst w pokrętle. Więc dla pozycji 0 wyłączamy tekst. Kolor można również ustawić, zastępując metodę getDropDownView. W ten sposób otrzymamy oczekiwany spinner.

Shravan Jain
źródło
0

Po prostu użyłbym RadioGroup z RadioButtons, jeśli masz tylko trzy opcje, możesz odznaczać je wszystkie na początku.

Stephane K.
źródło
0

Żadna z wcześniej przesłanych odpowiedzi nie działała tak, jak chciałem rozwiązać ten problem. Dla mnie idealnym rozwiązaniem byłoby „Wybierz jeden” (lub jakikolwiek inny tekst początkowy) przy pierwszym wyświetleniu pokrętła. Gdy użytkownik dotknie tarczy, tekst początkowy nie powinien być częścią wyświetlanego menu rozwijanego.

Aby jeszcze bardziej skomplikować moją szczególną sytuację, moje dane przędzarki pochodzą z kursora, który jest ładowany przez wywołania zwrotne LoaderManager.

Po znacznych eksperymentach wymyśliłem następujące rozwiązanie:

public class MyFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{

private static final String SPINNER_INIT_VALUE = "Select A Widget";
private Spinner mSpinner;
private int mSpinnerPosition;
private boolean mSpinnerDropDownShowing = false;
private View mSpinnerDropDown;

private MyCursorAdapter mCursorAdapter;

...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...

mCursorAdapter = new MyCursorAdapter(getActivity());

mSpinner = (Spinner) rootView.findViewById(R.id.theSpinner);
mSpinner.setOnTouchListener(mSpinnerTouchListener);
mSpinner.setAdapter(mCursorAdapter);

...
}

//Capture the touch events to toggle the spinner's dropdown visibility
private OnTouchListener mSpinnerTouchListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(mSpinnerDropDown != null && mSpinnerDropDownShowing == false){
            mSpinnerDropDownShowing = true;
            mSpinnerDropDown.setVisibility(View.VISIBLE);
        }
        return false;
    }
};

//Capture the click event on the spinner drop down items
protected OnClickListener spinnerItemClick = new OnClickListener(){

    @Override
    public void onClick(View view) {
        String widget = ((TextView) view.findViewById(android.R.id.text1)).getText().toString();

        if(!widget.equals(SPINNER_INIT_VALUE)){
            if(mCursorAdapter != null){
                Cursor cursor = mCursorAdapter.getCursor();
                if(cursor.moveToFirst()){
                    while(!cursor.isAfterLast()){
                        if(widget.equals(cursor.getString(WidgetQuery.WIDGET_NAME))){

                            ...

                            //Set the spinner to the correct item
                            mSpinnerPosition = cursor.getPosition() + 1;
                            mSpinner.setSelection(mSpinnerPosition);
                            break;
                        }
                        cursor.moveToNext();
                    }
                }
            }
        }

        //Hide the drop down. Not the most elegent solution but it is the only way I could hide/dismiss the drop down
        mSpinnerDropDown = view.getRootView();
        mSpinnerDropDownShowing = false;
        mSpinnerDropDown.setVisibility(View.GONE);
    }
};

private class MyCursorAdapter extends CursorAdapter {

    private final int DISPLACEMENT = 1;
    private final int DEFAULT_ITEM_ID = Integer.MAX_VALUE;

    private Activity mActivity;

    public MyCursorAdapter(Activity activity) {
            super(activity, null, false);
            mActivity = activity;
    }

    //When loading the regular views, inject the defualt item
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(position == 0){
            if(convertView == null){
                convertView = mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
            }
            return getDefaultItem(convertView);
        }
        return super.getView(position - DISPLACEMENT, convertView, parent);
    }

    //When loading the drop down views, set the onClickListener for each view
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent){
        View view = super.getDropDownView(position, convertView, parent);
        view.setOnClickListener(spinnerItemClick);
        return view;
    }

    //The special default item that is being injected
    private View getDefaultItem(View convertView){
        TextView text = (TextView) convertView.findViewById(android.R.id.text1);
        text.setText(SPINNER_INIT_VALUE);
        return convertView;
    }

    @Override
    public long getItemId(int position) {
        if (position == 0) {
            return DEFAULT_ITEM_ID;
        }
        return super.getItemId(position - DISPLACEMENT);
    }

    @Override
    public boolean isEnabled(int position) {
        return position == 0 ? true : super.isEnabled(position - DISPLACEMENT);
    }

    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount() + DISPLACEMENT;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return super.getViewTypeCount();
        }

        return super.getItemViewType(position - DISPLACEMENT);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor){

        if(cursor.isAfterLast()){
            return;
        }

        TextView text = (TextView) view.findViewById(android.R.id.text1);
        String WidgetName = cursor.getString(WidgetQuery.WIDGET_NAME);
        text.setText(WidgetName);
    }
}
}
Jed
źródło
0

Poradzę sobie z tym za pomocą przycisku zamiast pokrętła. Mam przykładowy projekt na GitHub.

W projekcie wyświetlam zarówno pokrętło, jak i przycisk, aby pokazać, że rzeczywiście wyglądają identycznie. Z wyjątkiem przycisku możesz ustawić tekst początkowy na cokolwiek chcesz.

Oto jak wygląda aktywność:

package com.stevebergamini.spinnerbutton;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Spinner;

public class MainActivity extends Activity {

    Spinner spinner1;
    Button button1;
    AlertDialog ad;
    String[] countries;

    int selected = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        spinner1 = (Spinner) findViewById(R.id.spinner1);
        button1 = (Button) findViewById(R.id.button1);

        countries = getResources().getStringArray(R.array.country_names);

        //  You can also use an adapter for the allert dialog if you'd like
        //  ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, countries);        

        ad = new AlertDialog.Builder(MainActivity.this).setSingleChoiceItems(countries, selected,  
                new  DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            button1.setText(countries[which]);
                            selected = which;
                            ad.dismiss();

                        }}).setTitle(R.string.select_country).create(); 


        button1.setOnClickListener( new OnClickListener(){

            @Override
            public void onClick(View v) {
                ad.getListView().setSelection(selected);
                ad.show();              
            }});

    }

}

UWAGA: Tak, zdaję sobie sprawę, że zależy to od zastosowanego motywu, a wygląd będzie nieco inny, jeśli użyjesz motywu Theme.Holo. Jeśli jednak używasz jednego ze starszych motywów, takiego jak Theme.Black, możesz zacząć.

SBerg413
źródło
0

jeśli napotykasz ten problem, gdy elementy są wypełniane kursorem bazy danych ,

najprostsze rozwiązanie, które znalazłem w tej SO odpowiedzi:

użyj UNION w zapytaniu adaptera kursora i dodaj dodatkowy element o id = -1 do wyniku zapytania, tak naprawdę nie dodając go do DB:

coś jak:

db.rawQuery ("SELECT iWorkerId jako _id, nvLastName jako nazwa FROM Worker w UNION SELECT -1 jako _id, '' as name", null);

jeśli wybrany element to -1, to jest to wartość domyślna. W przeciwnym razie jest to zapis ze stołu.

dvrm
źródło
0

Wydaje się to banalnym rozwiązaniem, ale zwykle umieszczam po prostu TextView na przedniej części tarczy. Cały Xml wygląda tak. (hej, nie strzelajcie do mnie, wiem, że niektórym z was nie podoba się tego rodzaju małżeństwo):

<FrameLayout
    android:id="@+id/selectTypesLinear"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <Spinner
        android:id="@+id/spinnerExercises"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:entries="@array/exercise_spinner_entries"
        android:prompt="@string/exercise_spinner_prompt"
     />                         
    <TextView
        android:id="@+id/spinnerSelectText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hey! Select this guy!"
        android:gravity="center"
        android:background="#FF000000" />


</FrameLayout>

Następnie ukrywam TextView, gdy element został wybrany. Oczywiście kolor tła TextView powinien być taki sam jak Spinner. Działa na Androidzie 4.0. Nie wiem o starszych wersjach.

Tak. Ponieważ Spinner wywołuje na początku setOnItemSelectedListener, ukrywanie widoku tekstu może być nieco trudne, ale można to zrobić w ten sposób:

    Boolean controlTouched;

    exerciseSpinner.setOnTouchListener(new OnTouchListener() {


        @Override
        public boolean onTouch(View v, MotionEvent event) {
            controlTouched = true; // I touched it but but not yet selected an Item.
            return false;
        }

    });
    exerciseSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            if (controlTouched) { // Are you sure that I touched it with my fingers and not someone else  ?
                spinnerSelText.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {
        }

    });
Claudio Ferraro
źródło
0

dla mnie zadziałało coś takiego. ma ulepszenie, które zmienia tylko tekst w NIEKTÓRYCH opcjach, ale nie we wszystkich.

Najpierw biorę nazwy pokrętła i tworzę arrayadapter z dostosowanym widokiem, ale nie ma to teraz znaczenia, klucz zastępuje getView, a wewnątrz zmieniam wartości, które musisz zmienić. W moim przypadku był tylko pierwszy, resztę pozostawiam oryginał

public void rellenarSpinnerCompeticiones(){
        spinnerArrayCompeticiones = new ArrayList<String>();
        for(Competicion c: ((Controlador)getApplication()).getCompeticiones()){
            spinnerArrayCompeticiones.add(c.getNombre());
        }
        //ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this,R.layout.spinner_item_competicion,spinnerArrayCompeticiones);
        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item_competicion, spinnerArrayCompeticiones){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                final View v = vi.inflate(R.layout.spinner_item_competicion, null);
                final TextView t = (TextView)v.findViewById(R.id.tvCompeticion);
                if(spinnerCompeticion.getSelectedItemPosition()>0){
                    t.setText(spinnerArrayCompeticiones.get(spinnerCompeticion.getSelectedItemPosition()));
                }else{
                    t.setText("Competiciones");
                }
                return v;
            }
        };
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerCompeticion.setAdapter(spinnerArrayAdapter);
    }
Rako
źródło
0

tutaj jest prosty

    private boolean isFirst = true;
private void setAdapter() {
    final ArrayList<String> spinnerArray = new ArrayList<String>();     
    spinnerArray.add("Select your option");
    spinnerArray.add("Option 1");
    spinnerArray.add("Option 2");
    spin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            TextView tv = (TextView)selectedItemView;
            String res = tv.getText().toString().trim();
            if (res.equals("Option 1")) {
            //do Something
        } else if (res.equals("Option 2")) {
            //do Something else
        }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) { }

    });

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.my_spinner_style,spinnerArray) {
         public View getView(int position, View convertView, ViewGroup parent) {
             View v = super.getView(position, convertView, parent);
             int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());                  
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).getLayoutParams().height = height;
             ((TextView) v).setGravity(Gravity.CENTER);
             ((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP, 19);
             ((TextView) v).setTextColor(Color.WHITE);
             return v;
         }

         public View getDropDownView(int position, View convertView,
                 ViewGroup parent) {
             if (isFirst) {
                 isFirst = false;
                 spinnerArray.remove(0);
             }
             View v = super.getDropDownView(position, convertView, parent);                  
             ((TextView) v).setTextColor(Color.argb(255, 70, 70, 70));
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).setGravity(Gravity.CENTER);
             return v;
         }
     };
     spin.setAdapter(adapter);
}
Sayka
źródło
0

Odwołaj się do jednej z powyższych odpowiedzi: https://stackoverflow.com/a/23005376/1312796

Dodałem swój kod, aby naprawić mały błąd. Tam, gdzie nie odzyskano żadnych danych .. Jak wyświetlić tekst zachęty ..!

Oto moja sztuczka ... Działa ze mną dobrze. !

Spróbuj umieścić swój spinner w Relative_layout i wyrównaj widok tekstowy ze swoim pokrętłem i graj z widocznością widoku tekstowego (POKAŻ / UKRYJ) za każdym razem, gdy adapter przędzarki jest załadowany lub pusty.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:background="#ededed"
android:orientation="vertical">



    <TextView
        android:id="@+id/txt_prompt_from"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textColor="@color/gray"
        android:textSize="16sp"
        android:layout_alignStart="@+id/sp_from"
        android:text="From"
        android:visibility="gone"/>

    <Spinner
        android:id="@+id/sp_from"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        />

Oto kod:

  txt__from = (TextView) rootView.findViewById(R.id.txt_prompt_from);

wywołać tę metodę przed i przed załadowaniem i opróżnieniem adaptera przędzarki.

setPromptTextViewVisibility (); //True or fales 

public void setPromptTextViewVisibility (boolean visible )
{
    if (visible)
    {
        txt_from.setVisibility(View.VISIBLE);
    }
    else
    {
        txt_from.setVisibility(View.INVISIBLE);
    }

}
Ibrahim AbdelGawad
źródło