Làm cách nào để tạo một Spinner Android với văn bản ban đầu Chọn Chọn One?


569

Tôi muốn sử dụng Spinner ban đầu (khi người dùng chưa thực hiện lựa chọn) hiển thị nội dung "Chọn một". Khi người dùng nhấp vào spinner, danh sách các mục được hiển thị và người dùng chọn một trong các tùy chọn. Sau khi người dùng thực hiện lựa chọn, mục đã chọn sẽ được hiển thị trong Spinner thay vì "Chọn một".

Tôi có đoạn mã sau để tạo Spinner:

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

Với mã này, ban đầu mục "Một" được hiển thị. Tôi chỉ có thể thêm một mục mới "Chọn một" vào các mục, nhưng sau đó "Chọn một" cũng sẽ được hiển thị trong danh sách thả xuống dưới dạng mục đầu tiên, đó không phải là điều tôi muốn.

Làm thế nào tôi có thể khắc phục vấn đề này?


6
Giải pháp hoàn hảo nằm trong câu hỏi này: stackoverflow.com/questions/9863378/ Chỉ cần ghi đè phương thức getDropDownView ().
Sourab Sharma

Bạn đã thử đặt phần tử đầu tiên của bộ chuyển đổi thành "Chọn một" chưa?
IgorGanapolsky

[Ở đây khác giải pháp tốt đẹp tuyệt vời!] [1] [1]: stackoverflow.com/questions/9863378/...
AirtonCarneiro

spinner có thể tái sử dụng: github.com/henrychuangtw/ReuseSpinner
HenryChuang

Câu trả lời:


255

Đây là một giải pháp chung ghi đè lên Spinnerquan điểm. Nó ghi đè setAdapter()để đặt vị trí ban đầu thành -1 và ủy quyền cho vị trí được cung cấpSpinnerAdapter để hiển thị chuỗi dấu nhắc cho vị trí nhỏ hơn 0.

Điều này đã được thử nghiệm trên Android 1.5 đến 4.2, nhưng người mua hãy cẩn thận! Bởi vì giải pháp này dựa vào sự phản ánh để gọi riêng tư AdapterView.setNextSelectedPositionInt()AdapterView.setSelectedPositionInt() , nó không được bảo đảm để hoạt động trong các bản cập nhật hệ điều hành trong tương lai. Có vẻ như nó sẽ, nhưng nó không có nghĩa là được bảo đảm.

Thông thường tôi sẽ không tha thứ như thế này, nhưng câu hỏi này đã được hỏi đủ lần và có vẻ như đó là một yêu cầu đủ hợp lý mà tôi nghĩ rằng tôi sẽ đăng giải pháp của mình.

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

7
@emmby Bạn có biết làm thế nào để xóa lựa chọn sau khi người dùng thiết lập nó không? Tôi đã thử tái cấu trúc hai lệnh gọi invoke () thành một phương thức ClearSelection (), nhưng nó không thực sự hoạt động. Mặc dù danh sách bật lên hiển thị mục được chọn trước đó là không được chọn, tiện ích con quay vẫn hiển thị mục đó như đã chọn và nếu người dùng chọn lại mục tương tự, onItemSelected () sẽ không được gọi.
Qwertie

3
một số có thể giải thích làm thế nào để sử dụng trên lớp?
Bishan

4
Giải pháp này không hoàn hảo 100% trên Android 4.2 (Cyanogenmod 10.1), sử dụng android: mục. Chiều cao của TextView bị thổi phồng nhỏ hơn chiều cao của tài nguyên mặc định của Bộ điều hợp mặc định. Vì vậy, khi bạn thực sự chọn một tùy chọn, chiều cao sẽ tăng, ~ 10px trong Galaxy S của tôi, không chấp nhận được. Tôi đã thử một vài thứ (trọng lực, đệm, lề, v.v.) và không có cách nào hoạt động đáng tin cậy trên các thiết bị, vì vậy tôi sẽ chọn một giải pháp khác.
Maragues

3
@DavidDoria Bạn phải sử dụng lớp NoDefaultSpinner trong tệp bố cục của mình. Sao chép nguồn từ bên trên vào dự án của bạn, ví dụ vào gói com.example.customview. Bây giờ trong bố cục xml của bạn, thay vì <Spinner ...> hãy sử dụng <com.example.customview.NoDefaultSpinner ...> Phần còn lại của mã có thể giữ nguyên. Đừng quên thêm thuộc tính android: prompt vào chế độ xem <com.example.customview.NoDefaultSpinner> trong bố cục của bạn.
Rực rỡ

2
@emmby spinnerBrand.setSelection (-1); không hoạt động
Sachin C

291

Những gì bạn có thể làm là trang trí của bạn SpinnerAdapter bằng một cái hiển thị 'Chọn Tùy chọn ...' Xem ban đầu để Spinner hiển thị mà không có gì được chọn.

Dưới đây là một ví dụ hoạt động được thử nghiệm cho Android 2.3 và 4.0 (nó không sử dụng gì trong thư viện tương thích, vì vậy nó sẽ ổn trong một thời gian) Vì nó là một công cụ trang trí, nên dễ dàng trang bị thêm mã hiện có và nó cũng hoạt động tốt với CursorLoaders. (Hoán đổi con trỏ trên bọc cursorAdaptertất nhiên ...)

Có một lỗi Android khiến cho việc sử dụng lại lượt xem khó khăn hơn một chút. (Vì vậy, bạn phải sử dụng setTaghoặc một cái gì đó khác để đảm bảo convertViewchính xác.) Spinner không hỗ trợ nhiều kiểu xem

Mã ghi chú: 2 constructor

Điều này cho phép bạn sử dụng một dấu nhắc tiêu chuẩn hoặc xác định 'không có gì được chọn' của riêng bạn làm hàng đầu tiên hoặc cả hai hoặc không. (Lưu ý: Một số chủ đề hiển thị DropDown cho Spinner thay vì hộp thoại. Dropdown thường không hiển thị lời nhắc)

Bạn xác định bố cục để 'trông' giống như một dấu nhắc, ví dụ, chuyển sang màu xám ...

Ban đầu không có gì được chọn

Sử dụng một dấu nhắc tiêu chuẩn (lưu ý rằng không có gì được chọn):

Với một dấu nhắc tiêu chuẩn

Hoặc với một dấu nhắc và một cái gì đó động (có thể không có dấu nhắc nào):

Nhắc và không có gì được chọn hàng

Cách sử dụng trong ví dụ trên

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_noth_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...]" />

Không có gì được chọnSpinnerAd Module.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.
    }

}

52
Đây là một giải pháp tao nhã cho vấn đề. Mã hoạt động chính xác như copy'n'piled vào dự án của tôi. +1 không cần phản ánh.
Richard Le Mesurier

2
Đây là một giải pháp tuyệt vời. Nếu bất cứ ai muốn biết cách ghi đè tiêu đề không chỉ trước khi một mục được chọn, mà tại mọi thời điểm, trong lệnh gọi getView (), chỉ cần trả lại getNothSelectedView (hoặc bất kỳ chế độ xem tùy chỉnh nào khác). Danh sách thả xuống sẽ vẫn được điền với các mục từ bộ điều hợp của bạn, nhưng bây giờ bạn có thể kiểm soát tiêu đề SAU một cái gì đó cũng được chọn.
OldSchool4664

6
Đây là một giải pháp thực sự thanh lịch cho một vấn đề không nên tồn tại (thử phát triển Iphone). Tuyệt vời và cảm ơn! Vui mừng vì ai đó đã nhớ các mẫu, v.v.
user1700737

3
@prashantwosti, mã đã được cập nhật để hoạt động với Lollipop. Cụ thể getItemViewType () và getViewTypeCount ().
aaronvargas 17/1/2015

3
@aaronvargas một khi đã chọn một mục từ công cụ quay vòng, tôi có thể hoàn tác và chọn "[Chọn một hành tinh]" không?
modabeckham

130

Tôi đã kết thúc bằng cách sử dụng một Buttonthay thế. Trong khi a Buttonkhông phải là một Spinner, hành vi rất dễ tùy chỉnh.

Đầu tiên tạo Adaptor như bình thường:

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

Lưu ý rằng tôi đang sử dụng simple_spinner_dropdown_itemlàm id bố cục. Điều này sẽ giúp tạo ra một cái nhìn tốt hơn khi tạo hộp thoại cảnh báo.

Trong trình xử lý onClick cho Nút của tôi, tôi có:

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

Và đó là nó!


10
Tôi đồng ý với câu trả lời đó. Bên cạnh đó, một nút dễ tạo kiểu hơn nhiều so với Spinner.
Romain Piel

@HRJ Tôi đã thực hiện theo cách bạn đề xuất, nhưng mục được chọn trước đó không được tô sáng (có nghĩa là nút radio phải được làm sáng bằng dấu greeen ở giữa) .... Làm cách nào tôi có thể hiểu được điều này trong phương pháp OnClick () cái nút. Xin hãy giúp tôi HRJ .....
Avadhani Y

2
Nút có bố cục này thật hoàn hảo nền = "@ android: drawable / btn_dropdown" android: text = "@ string / city_prompt" />
kml_ckr

Làm thế nào bạn sẽ cập nhật văn bản của nút để phản ánh lựa chọn, như sẽ xảy ra trong một spinner?
shim

3
giải pháp cho vấn đề: thay vì SetAd CHƯƠNG, hãy sử dụng SetSingleChoiceItems
Grzegorz Dev

67

Đầu tiên, bạn có thể quan tâm đến promptthuộc tính của Spinnerlớp. Xem hình dưới đây, "Chọn một hành tinh" là lời nhắc có thể được đặt trong XML bằng android:prompt="".

nhập mô tả hình ảnh ở đây

Tôi sẽ đề xuất phân lớp Spinner, trong đó bạn có thể duy trì hai bộ điều hợp bên trong. Một bộ điều hợp có tùy chọn "Chọn một" và bộ điều hợp thực khác (với các tùy chọn thực tế), sau đó sử dụng OnClickListenerđể chuyển đổi bộ điều hợp trước khi hộp thoại lựa chọn được hiển thị. Tuy nhiên, sau khi thử thực hiện ý tưởng đó, tôi đã đi đến kết luận rằng bạn không thể nhận OnClickcác sự kiện cho chính widget.

Bạn có thể bọc spinner trong một chế độ xem khác, chặn các nhấp chuột trên chế độ xem và sau đó yêu cầu bạn CustomSpinnerchuyển đổi bộ điều hợp, nhưng có vẻ như là một vụ hack khủng khiếp.

Bạn có thực sự cần hiển thị "Chọn một" không?


36
Đây không chỉ là vấn đề cần hiển thị "Chọn một", mà còn giải quyết trường hợp giá trị spinner có thể tùy ý để trống.
greg7gkb

5
Ngoài ra, với tùy chọn này, Trái đất được hiển thị là lựa chọn trên Spinner trước khi mọi thứ được chọn, đối với ứng dụng của tôi, tôi muốn người dùng có thể nói rằng họ chưa chọn bất cứ điều gì
dylan murphy

2
Điều này không thực sự trả lời câu hỏi. mọi người đang tìm cách để có spinner theo mặc định hiển thị "Chọn một" thay vì mục đầu tiên trong danh sách các hành tinh, trong ví dụ này
JMRboosties

58

Mã này đã được thử nghiệm và hoạt động trên Android 4.4

nhập mô tả hình ảnh ở đây

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

getItem(getCount())gạch chân màu đỏ cho tôi? Không thể giải quyết phương thức setHint
Zapnologica

Tôi có một nghi ngờ, đã thấy nhiều giải pháp trong chủ đề này..nhưng tại sao mọi người lại thêm gợi ý cho đến cuối cùng. Có sai không khi thêm gợi ý ở hàng đầu tiên?
akashPatra

Tôi không thể đặt 'setOnItemSelectedListener (cái này);' vì tôi đang sử dụng 'implements NavigationView.OnNavlationItemSelectedListener', tôi có thể xóa 'setOnItemSelectedListener (this);' không có vấn đề gì?
CGR

@akashpatra Lý do họ thêm gợi ý cuối cùng là vì ArrayAd CHƯƠNG cho spinner có thể nhận các giá trị của nó từ các nguồn khác nhau trong thời gian chạy.
VinKrish

điều này thực sự giúp tôi
sunil

31

Tôi tìm thấy giải pháp này:

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

Chỉ cần thay đổi mảng [0] bằng "Chọn một" và sau đó trong onItemSelected, đổi tên nó thành "Một".

Không phải là một giải pháp đẳng cấp, nhưng nó hoạt động: D


5
Điều này đã không làm việc cho tôi. Sau khi chọn mục "Một", nó vẫn báo "Chọn một".
Leo Landau

Điều này sẽ không hoạt động vì giao diện onItemSelected sẽ gọi lần đầu tiên luôn.
Vaibhav Kadam

20

Không có API mặc định để đặt gợi ý về Spinner. Để thêm nó, chúng ta cần một cách giải quyết nhỏ mà không thực hiện phản ánh an toàn

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

Nguồn bộ điều hợp:

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

Nguồn chính thức


R.id.text1 là gì? đó là bất kỳ bố trí hoặc xem? vui lòng giải thích câu trả lời của bạn
Anand Savigate

Nó nên làandroid.R.id.text1
Yakiv Mospan

Tôi có một nghi ngờ, đã thấy nhiều giải pháp trong chủ đề này..nhưng tại sao mọi người lại thêm gợi ý cho đến cuối cùng. Có sai không khi thêm gợi ý ở hàng đầu tiên?
akashPatra

@akashpatra Tôi không nhớ chính xác, nhưng dường như có một số vấn đề khi tôi cố gắng biến nó thành danh sách vật phẩm đầu tiên. Dù sao, bạn luôn có thể thử nó và nhận xét ở đây, tất cả các phép thuật ở đây là xung quanh getCountphương pháp
Yakiv Mospan

@YakivMospan Tôi nhận được một NPE khi tôi sử dụng cái này, có lẽ là do Reflection khi sử dụng ProGuard. Bạn có biết làm sao để sửa cái này không?
Alan

17

Có rất nhiều câu trả lời ở đây nhưng tôi ngạc nhiên không ai đề xuất một giải pháp đơn giản: Đặt TextView lên trên Spinner. Đặt một trình nghe nhấp chuột trên TextView ẩn TextView hiển thị Spinner và gọi spinner.performClick ().


9

Tôi gặp vấn đề tương tự đối với spinner, với một lựa chọn trống và tôi tìm thấy một giải pháp tốt hơn. Có một cái nhìn vào mã đơn giản này.

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

Ở đây spinnerad CHƯƠNG là một tùy chỉnh nhỏ cho mảng. Nó trông như thế này:

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

6
Vấn đề với cách tiếp cận này là nó vẫn chọn mục đầu tiên trong danh sách khi danh sách bật lên. Bởi vì điều đó đã được chọn, bạn không thể chạm vào nó để chọn - nó hoạt động như thể không có lựa chọn nào xảy ra.
jwadsack

7

Bạn có thể thay đổi nó thành Dạng xem văn bản và sử dụng:

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

và sau đó xác định android:texttài sản.


Chỉ hoạt động cho API 14 trở lên.
Giulio Piancastelli

6

Tệp XML:

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

Hoạt động:

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

Một số chức năng (thêm các thứ vào bộ điều hợp theo chương trình)>

featuresAdapter.add("some string");

Bây giờ bạn có một spinner trống và bạn có thể viết mã để không mở hộp thoại nếu trống. Hoặc họ có thể nhấn lại. Nhưng bạn cũng điền nó với một chức năng hoặc một danh sách khác trong thời gian chạy.


Ngoài ra, không cần phải thông báoDataSetChanged () vì nó phải được đặt thành đúng theo mặc định.
trgraglia

4

Tôi đã thử như sau. Lấy một nút và đưa ra sự kiện nhấp vào nó. Bằng cách thay đổi nền nút, nó dường như là một spinner.

Khai báo dưới dạng biến toàn cục alertdialog và giá trị mặc định ..

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

4

Đây là cách của tôi:

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

Điều này mở spinner ở vị trí dưới cùng
SpyZip

3

Hãy xem ứng dụng iosched cho một giải pháp cho mục đích chung để thêm một yếu tố vào đầu danh sách. Cụ thể, nếu bạn đang sử dụng CthonAd CHƯƠNG , hãy xem TrackAd Module.java mở rộng định nghĩa đó để cung cấp phương thức "setHasAllItem" và mã liên quan để quản lý số lượng danh sách để xử lý mục bổ sung ở trên cùng.

Sử dụng bộ điều hợp tùy chỉnh, bạn có thể đặt văn bản thành "Chọn một" hoặc bất cứ điều gì khác mà bạn có thể muốn mục hàng đầu đó nói.


3

Tôi có một công cụ quay vòng trên tệp chính của tôi và id của nó là @+id/spinner1

đây là những gì tôi viết trong hàm OnCreate của mình:

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

Nó không cần bất kỳ thực hiện trong lớp.


3

Tôi tìm thấy nhiều giải pháp tốt cho việc này. hầu hết đang hoạt động bằng cách thêm một mục vào cuối bộ điều hợp và không hiển thị mục cuối cùng trong danh sách thả xuống. Vấn đề lớn đối với tôi là danh sách thả xuống của spinner sẽ bắt đầu từ cuối danh sách. Vì vậy, người dùng nhìn thấy các mục cuối cùng thay vì các mục đầu tiên (trong trường hợp có nhiều mục để hiển thị), sau khi chạm vào spinner lần đầu tiên.

Vì vậy, tôi đặt mục gợi ý vào đầu danh sách. và ẩn mục đầu tiên trong danh sách thả xuống.

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

đặt bố cục bên dưới trong @Override getDropDownView () khi vị trí bằng 0, để ẩn hàng gợi ý đầu tiên.

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>

3

Ngoài ra, có một mẹo đơn giản để hiển thị mặc định:

Bạn có thể thêm một giá trị mặc định trong danh sách của bạn và sau đó thêm tất cả bộ sưu tập của bạn bằng cách sử dụng list.addAll(yourCollection);

Mẫu mã khả thi tại đây:

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

Hy vọng nó sẽ phục hồi sự phức tạp của bạn. Chúc mừng mã hóa!


2

Tôi nghĩ cách dễ nhất là tạo một mục giả trên chỉ số 0 với nội dung "chọn một" và sau đó lưu có thể kiểm tra xem lựa chọn đó có phải là 0 không.


4
Còn việc xem danh sách các mặt hàng thì sao? Bạn muốn xem vị trí "chọn một" ở trên cùng? Đó không chỉ là vấn đề tiết kiệm.
Krzysztof Wolny

@KrzysztofWolny Spinner theo mặc định hiển thị mục ở vị trí 0
rds

2

Vì vậy, đây là ví dụ cuối cùng của tôi "all-in" cho một công cụ tạo nút

Trong 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>

Trong chuỗi DOM

<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>

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

    }

}   

Cuối cùng tôi đã thu được một kích thước phông chữ có thể cấu hình không có mục đầu tiên có thể chọn nút spinner !!! Cảm ơn HRJ


1

Khi mở rộng SpinnerAdapter, bạn ghi đè hai Viewphương thức sản xuất getView(int, View, ViewGroup)getDropDownView(int, View, ViewGroup). Cái đầu tiên cung cấp Viewchèn vào Spinnerchính nó; cái thứ hai cung cấp Viewtrong danh sách thả xuống (như tên cho thấy). Bạn có thể ghi đè lên getView(...)để cho đến khi một mục được chọn, nó sẽ hiển thị TextViewmột dấu nhắc chứa; sau đó, khi bạn phát hiện một mục đã được chọn, bạn thay đổi nó để hiển thị một mục TextViewtương ứng với mục đó.

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

//...
}

1
Tôi đã phát hiện ra một lỗ hổng trong phương thức này: Spinner tự động chọn một mục ngay lập tức. Tôi sẽ tìm cách vượt qua điều này trong thời gian ngắn.
Andrew Wyld

Tôi đã nói quá sớm. Tôi đã không từ bỏ, tuy nhiên. Lưu ý rằng theo Spinnerhướng dẫn (được cho là hiển thị ToastSAU KHI bạn đã chọn một mục) OUGHT này để hoạt động: developer.android.com/resource/tutorials/view/iêu
Andrew Wyld

1

Đối với những người sử dụng Xamarin, đây là C # tương đương với câu trả lời của aaronvargas ở trên.

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

1

Tôi cũng đã giải quyết vấn đề này bằng cách sử dụng đoạn mã sau. Giả sử bạn đang có một danh sách các mục, vd

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

Bây giờ chúng tôi phải cung cấp các chuỗi cho spinner vì spinner không thể hiểu đối tượng. Vì vậy, chúng tôi sẽ tạo một danh sách mảng mới với các mục chuỗi như thế này ->

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

Bây giờ chúng ta có itemStringArrayListdanh sách mảng với hai mục chuỗi. Và chúng tôi phải hiển thị văn bản "Chọn mục" làm mục đầu tiên. Vì vậy, chúng ta phải chèn một chuỗi mới vào itemStringArrayList.

itemStringArrayList.add("Select Item");

Bây giờ chúng tôi có một danh sách mảng itemsArrayListvà chúng tôi muốn hiển thị hai yếu tố trong trình đơn thả xuống. Nhưng điều kiện ở đây là ... Nếu chúng ta không chọn bất cứ thứ gì thìSelect Item sẽ xuất hiện dưới dạng phần tử đầu tiên sẽ không được bật.

Vì vậy, chúng ta có thể thực hiện chức năng này như thế này. Nếu bạn cần tải các mục danh sách mảng vào spinner android. Vì vậy, bạn sẽ phải sử dụng một số bộ chuyển đổi. Vì vậy, ở đây tôi sẽ sử dụng ArrayAdapter. Chúng tôi cũng có thể sử dụng bộ điều hợp tùy chỉnh.

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

Ở đây trong mã này. chúng tôi đang sử dụng bố trí spinner tùy chỉnh tức là R.layout.spinner_item. Đó là một chế độ xem văn bản đơn giản

<?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"
    />

Chúng ta cần phải vô hiệu hóa văn bản đầu tiên trong spinner. Vì vậy, đối với vị trí 0, chúng tôi đang vô hiệu hóa văn bản. Và màu sắc chúng ta cũng có thể thiết lập bằng cách giám sát phương thức getDropDownView. Vì vậy, theo cách này, chúng tôi sẽ nhận được spinner dự kiến.


0

Tôi chỉ sử dụng một Radiogroup với RadioButtons nếu bạn chỉ có ba lựa chọn, ban đầu bạn có thể làm cho tất cả chúng không được chọn.


0

Không có câu trả lời nào được gửi trước đây thực sự hoạt động theo cách tôi muốn giải quyết vấn đề này. Đối với tôi, giải pháp lý tưởng sẽ cung cấp cho Chọn Chọn Một (hoặc bất kỳ văn bản ban đầu nào) khi trình duyệt được hiển thị lần đầu tiên. Khi người dùng chạm vào công cụ quay vòng, văn bản ban đầu không nên là một phần của trình đơn thả xuống được hiển thị.

Để làm phức tạp thêm tình huống cụ thể của tôi, dữ liệu spinner của tôi sắp trở thành một con trỏ được tải thông qua các cuộc gọi lại LoaderManager.

Sau khi thử nghiệm đáng kể, tôi đã đưa ra giải pháp sau đây:

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

0

Tôi xử lý việc này bằng cách sử dụng nút thay vì Spinner. Tôi có dự án mẫu trên GitHub.

Trong dự án, tôi đang hiển thị cả Spinner và nút để cho thấy rằng chúng thực sự trông giống hệt nhau. Ngoại trừ nút, bạn có thể đặt văn bản ban đầu thành bất cứ điều gì bạn muốn.

Đây là những gì các hoạt động trông như:

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

    }

}

LƯU Ý: Có, tôi nhận ra rằng điều này phụ thuộc vào Chủ đề được áp dụng và giao diện sẽ hơi khác nếu sử dụng Theme.Holo. Tuy nhiên, nếu bạn đang sử dụng một trong những chủ đề cũ như Theme.Black, bạn sẽ ổn.


0

nếu bạn gặp phải vấn đề này khi các mục của bạn được điền từ con trỏ cơ sở dữ liệu ,

giải pháp đơn giản nhất mà tôi tìm thấy trong này câu trả lời SO :

sử dụng UNION trong truy vấn bộ điều hợp con trỏ của bạn và thêm mục bổ sung có id = -1 vào kết quả truy vấn mà không thực sự thêm nó vào DB:

cái gì đó như:

db.rawQuery ("CHỌN iWorkerId là _id, nvLastName làm tên TỪ Công nhân w UNION SELECT -1 dưới dạng _id, '' như tên", null);

nếu mục được chọn là -1, thì đó là giá trị mặc định. Nếu không thì đó là một bản ghi từ bảng.


0

Có vẻ là một giải pháp tầm thường nhưng tôi thường đặt một TextView đơn giản ở phía trước của spinner. Toàn bộ Xml trông như thế này. (này các bạn, đừng bắn tôi, tôi biết rằng một số bạn không thích kiểu hôn nhân này):

<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>

Sau đó, tôi ẩn TextView khi một Mục được chọn. Rõ ràng màu nền của TextView phải giống với Spinner. Hoạt động trên Android 4.0. Không biết trên các phiên bản cũ hơn.

Đúng. Bởi vì Spinner gọi setOnItemSelectedListener ngay từ đầu, việc ẩn văn bản có thể hơi khó khăn một chút, nhưng có thể được thực hiện theo cách này:

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

    });

0

Đối với tôi nó đã làm việc như thế này. có cải tiến chỉ thay đổi văn bản trong MỘT SỐ tùy chọn, không phải trong tất cả.

Đầu tiên tôi lấy tên của spinner và tạo mảng với chế độ xem tùy chỉnh, nhưng bây giờ không thành vấn đề, khóa là ghi đè getView và bên trong thay đổi các giá trị bạn cần thay đổi. Trong trường hợp của tôi chỉ là người đầu tiên, phần còn lại tôi để lại bản gốc

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

0

đây là một đơn giản

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

0

Tham khảo một trong những câu trả lời trên: https://stackoverflow.com/a/23005376/1312796

Tôi đã thêm mã của tôi để sửa một lỗi nhỏ. Đó là nơi không có dữ liệu được lấy .. Làm thế nào để hiển thị văn bản nhanh chóng ..!

Đây là Thủ thuật của tôi ... Nó hoạt động tốt với tôi. !

Cố gắng đặt spinner của bạn vào Relative_layout và căn chỉnh Textview với spinner của bạn và chơi với khả năng hiển thị của Textview (SHOW / HIDE) bất cứ khi nào bộ điều hợp của spinner được tải hoặc trống..Like this:

<?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"
        />

Đây là mã:

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

gọi phương thức này sau và trước khi bộ điều hợp spinner được tải và trống.

setPromptTextViewVisibility (); //True or fales 

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.