Android Spinner: Tránh các cuộc gọi onItemSelected trong khi khởi tạo


156

Tôi đã tạo một ứng dụng Android với a Spinnervà a TextView. Tôi muốn hiển thị mục đã chọn từ danh sách thả xuống của Spinner trong TextView. Tôi đã triển khai Spinner trong onCreatephương thức để khi tôi chạy chương trình, nó sẽ hiển thị một giá trị trong TextView(trước khi chọn một mục từ danh sách thả xuống).

Tôi chỉ muốn hiển thị giá trị trong TextView sau khi chọn một mục từ danh sách thả xuống. Làm thế nào để tôi làm điều này?

Đây là mã của tôi:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class GPACal01Activity extends Activity implements OnItemSelectedListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);

        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
        TextView textView = (TextView) findViewById(R.id.textView1);
        String str = (String) parent.getItemAtPosition(pos);
        textView.setText(str);
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO Auto-generated method stub

    }
}

spinners luôn có một giá trị được chọn mặc định, nếu bạn muốn có một spinner không có giá trị được chọn mặc định, bạn nên tạo spinner tùy chỉnh của bạn hoặc tạo một spinner tùy chỉnh với một mục trống và trong phương thức getView (), thay đổi mức độ hiển thị của bố cục thô cho
Gone

4
Làm thế nào mà một lỗi khó chịu như vậy vẫn tồn tại vào cuối năm 2018 ???
người dùng-123

Câu trả lời:


174
spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

Vì vậy, lần đầu tiên xử lý việc này với bất kỳ giá trị Integer nào

Ví dụ: Ban đầu dùng int check = 0;

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
   if(++check > 1) {
      TextView textView = (TextView) findViewById(R.id.textView1);
      String str = (String) parent.getItemAtPosition(pos);
      textView.setText(str);
   }
}

Bạn có thể làm điều đó với giá trị boolean và cũng bằng cách kiểm tra các vị trí hiện tại và trước đó. Xem tại đây


2
Người đàn ông tuyệt vời..khi lần đầu tiên tôi phải đối mặt với vấn đề này, tôi đã cố gắng thực hiện spinner tùy chỉnh..nhưng nó không hoạt động..nhưng giải pháp của bạn hoạt động như một bùa mê..Cảm ơn.
Sash_KP

1
Bạn khai báo séc ở đâu? Bên ngoài getView ()? Bên trong viewHolder? Ở đâu? đã thử giải pháp của bạn nhưng không hiệu quả với tôi.
dùng3718908

9
Tôi đoán đó là một bản vá không phải là một giải pháp.
saksham

1
Tôi đang đối mặt với vấn đề tương tự. Đây có phải là một loại lỗi? Ngoài ra nếu tôi chọn cùng một mục nhiều lần, người nghe không hoạt động sau lần đầu tiên. Nó chỉ hoạt động nếu mục lựa chọn thay đổi. Bất kỳ bình luận, giúp đỡ?
amitava

1
Tôi đã thử giải pháp này với cùng một vấn đề của mình, nhưng cái chảo này chỉ có một, ví dụ: khi tôi có 2 mục thả xuống, nó sẽ rung lên khi tôi chọn bất kỳ mục spinner nào lần đầu tiên, khi tôi thử lần thứ 2 thì nó không hoạt động đúng
Waseem

116

Chỉ cần đặt dòng này trước khi đặt OnItemSelectedListener

spinner.setSelection(0,false)

7
Nó sẽ là một câu trả lời tốt hơn nếu bạn viết nó giúp như thế nào và tại sao.
dùng3533716

1
Nó giúp, nhưng muốn làm thế nào?
AEMLoviji

14
Điều này hoạt động vì trước tiên bạn đặt lựa chọn, sau đó thêm người nghe, nhưng người nghe sẽ không được gọi vì bạn đã chọn lựa chọn này trước đó. Chỉ những lựa chọn mới sẽ gọi người nghe.
nhà phát triển Android

4
Điều này hoạt động vì setSelection(int, boolean)các cuộc gọi setSelectionInt()nội bộ, và bạn cần đặt người nghe sau (thay vì trước) gọi này. Coi chừng điều đó setSelection(int)không hiệu quả, bởi vì nó gọi setNextSelectedPositionInt()nội bộ, và đây là điều đã dẫn tôi đến đây.
Hai Zhang

3
Điều này không hoạt động nếu nó được khai báo trong hoặc trước onCreateView (). onItemSelected sẽ được gọi.
Arash

62

Bắt đầu với API cấp 3, bạn có thể sử dụng onUserInteraction () trên một Hoạt động với boolean để xác định xem người dùng có tương tác với thiết bị hay không.

http://developer.android.com/reference/android/app/Activity.html#onUserInteraction ()

@Override
public void onUserInteraction() {
     super.onUserInteraction();
     userIsInteracting = true;
}

Là một lĩnh vực trong Hoạt động tôi có:

 private boolean userIsInteracting;

Cuối cùng, spinner của tôi:

      mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

           @Override
           public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
                spinnerAdapter.setmPreviousSelectedIndex(position);
                if (userIsInteracting) {
                     updateGUI();
                }
           }

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

           }
      });

Khi bạn đến và đi qua hoạt động, boolean được đặt lại thành false. Hoạt động như một lá bùa.


3
Bill tốt .. Tôi nghĩ rằng đây là giải pháp tốt hơn câu trả lời được chấp nhận
Ritesh Gune

bạn lấy setmPreinglySelected Index ở đâu?!?!
TheQ

Typo? :) setPreinglySelected Index ()
Bill Mote

4
Điều này sẽ không hoạt động trong trường hợp các đoạn tổ vì onUserInteraction là phương thức Activity. Giải pháp nào khác?
Chitrang

1
@ErikB nvm, đã tìm ra rồi. Đặt nó sai bên trong người nghe hoạt động tốt.
Sikander

20

Điều này làm việc cho tôi

Khởi tạo của Spinner trong Android có vấn đề đôi khi vấn đề trên đã được giải quyết bằng mẫu này.

Spinner.setAdapter();
Spinner.setSelected(false);  // must
Spinner.setSelection(0,true);  //must
Spinner.setonItemSelectedListener(this);

Bộ điều hợp cài đặt phải là phần đầu tiên và onItemSelectedListener (phần này) sẽ là phần cuối cùng khi khởi tạo một công cụ quay vòng. Theo mẫu trên OnItemSelected () của tôi không được gọi trong quá trình khởi tạo spinner


11

haha ... tôi có cùng một câu hỏi Khi initViews () chỉ cần làm như thế này. Trình tự là chìa khóa, người nghe là người cuối cùng. Chúc may mắn !

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);

Một người tốt! Không có gì làm việc cho tôi bất cứ điều gì tôi đã áp dụng trước đây nhưng điều này đã làm việc cho tôi như một cơ duyên. Cảm ơn @TreeSouth
Deepika Lalra 14/07/2015

11
Đối với tôi đã làm việc spinner.setSelection (vị trí, sai) được sử dụng theo cùng một cách. Với phương thức setSelection (vị trí), trình nghe được gọi trong quá trình khởi tạo.
Mario Kutlev

2
@HugoGresse Hãy thử gọi spinner.setSelection (0, sai); . Điều đó là, bây giờ nó sẽ bỏ qua việc lựa chọn vị trí này, bởi vì nó đã được chọn
nhà phát triển Android

8

Giải pháp của tôi:

protected boolean inhibit_spinner = true;


@Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int pos, long arg3) {

            if (inhibit_spinner) {
                inhibit_spinner = false;
            }else {

            if (getDataTask != null) getDataTask.cancel(true);
            updateData();
            }

        }

7

Để tránh gọi spinner.setOnItemSelectedListener () trong quá trình khởi tạo

spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

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

    }
});

6

Bạn có thể làm điều này bằng cách này:

AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //set the text of TextView
        }

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

        }
    });

yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            yourSpinner.setOnItemSelectedListener(listener);
        }

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

        }
    });

Lúc đầu, tôi tạo một bộ lắng nghe và được gán cho một cuộc gọi lại thay đổi; sau đó tôi tạo một người nghe ẩn danh thứ hai và khi nó được gọi lần đầu tiên, điều này thay đổi người nghe =]


3

Cờ tương tác người dùng sau đó có thể được đặt thành đúng trong phương thức onTouch và đặt lại onItemSelected()sau khi thay đổi lựa chọn được xử lý. Tôi thích giải pháp này vì cờ tương tác người dùng được xử lý riêng cho công cụ quay vòng và không dành cho các chế độ xem khác trong hoạt động có thể ảnh hưởng đến hành vi mong muốn.

Trong mã:

Tạo trình nghe của bạn cho spinner:

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            userSelect = false;
            // Your selection handling code here
        }
    }

}

Thêm người nghe vào spinner như cả an OnItemSelectedListenervà an OnTouchListener:

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

2

Giải pháp đơn giản tương tự cho phép nhiều spinners là đặt Adaptor trong bộ sưu tập - trong siêu lớp Activity - trong lần thực hiện đầu tiên của onItemSelected (...) Sau đó kiểm tra xem Adaptor có nằm trong bộ sưu tập hay không trước khi thực hiện. Điều này cho phép một tập hợp các phương thức trong lớp cha và hỗ trợ nhiều Adaptor và cho nhiều spinners.

Siêu xe ...

private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();

   protected boolean firstTimeThrough(AdapterView parent) {
    boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
    if (firstTimeThrough) {
       AdapterViewCollection.add(parent);
     }
    return firstTimeThrough;
   }

Phân lớp ...

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
      if (! firstTimeThrough(parent)) {
        String value = safeString(parent.getItemAtPosition(pos).toString());
        String extraMessage = EXTRA_MESSAGE;
        Intent sharedPreferencesDisplayIntent = new         Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
    sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
    startActivity(sharedPreferencesDisplayIntent);
  }
  // don't execute the above code if its the first time through
  // do to onItemSelected being called during view initialization.

}


2

tạo một trường boolean

private boolean inispinner;

bên trong hoạt động

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!inispinner) {
                inispinner = true;
                return;
            }
            //do your work here
        }

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

        }
    });

2

Thử cái này

spinner.postDelayed(new Runnable() {
        @Override
        public void run() {
            addListeners();
        }
    }, 1000);.o

1

Bạn có thể đạt được nó bằng cách setOnTouchListener trước sau đó setOnItemSelectedListener trong onTouch

@Override
public boolean onTouch(final View view, final MotionEvent event) {
 view.setOnItemSelectedListener(this)
 return false;
}

Tôi thích điều này. Mặc dù nó tạo ra một trình nghe mới mỗi khi người dùng chạm vào khung nhìn. Vì vậy, tôi thích lưu trữ bộ lắng nghe được tạo đầu tiên và sử dụng lại nó.
Vlad

1

Điều này làm việc cho tôi:

    spinner.setSelection(0, false);
    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spinner.setOnItemSelectedListener(listener);
            }, 500);

1

Dựa trên câu trả lời của Abhi tôi đã làm cho người nghe đơn giản này

class SpinnerListener constructor(private val onItemSelected: (position: Int) -> Unit) : AdapterView.OnItemSelectedListener {

    private var selectionCount = 0

    override fun onNothingSelected(parent: AdapterView<*>?) {
        //no op
    }

    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        if (selectionCount++ > 1) {
           onItemSelected(position)
        }
    }
}

0

Có cùng một vấn đề và điều này làm việc cho tôi:

Tôi có 2 spinners và tôi cập nhật chúng trong khi init và trong khi tương tác với các điều khiển khác hoặc sau khi nhận dữ liệu từ máy chủ.

Đây là mẫu của tôi:

public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {

    private void removeSpinnersListeners() {
        spn1.setOnItemSelectedListener(null);
        spn2.setOnItemSelectedListener(null);
    }

    private void setSpinnersListeners() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spn1.setOnItemSelectedListener(MyClass.this);
                spn2.setOnItemSelectedListener(MyClass.this);
            }
        }, 1);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Your code here
    }

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

    }
}

Khi lớp đang bắt đầu sử dụng setSpinnersListener () thay vì trực tiếp thiết lập trình nghe.

Runnable sẽ ngăn spinner bắn vàoItemSelected ngay sau khi bạn đặt giá trị của chúng.

Nếu bạn cần cập nhật công cụ quay vòng (sau cuộc gọi máy chủ, v.v.), hãy sử dụng removeSpinnersListener () ngay trước các dòng cập nhật của bạn và setSpinnersListener () ngay sau các dòng cập nhật. Điều này sẽ ngăn onItemSelected bắn sau khi cập nhật.


0

spinner.setOnTouchListener(new View.OnTouchListener() { 
@Override public boolean onTouch(View view, MotionEvent motionEvent) { isSpinnerTouch=true; return false; }});

holder.spinner_from.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int slot_position, long l) {
                if(isSpinnerTouch)
                {
                    Log.d("spinner_from", "spinner_from");
                    spinnerItemClickListener.onSpinnerItemClickListener(position, slot_position, AppConstant.FROM_SLOT_ONCLICK_CODE);
                }
                else {

                }
            }

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

            }
        });

0

Đối với tôi, giải pháp của Abhi hoạt động tuyệt vời đến cấp độ Api 27.

Nhưng dường như từ Api cấp 28 trở lên, onItemSelected () không được gọi khi trình nghe được đặt, có nghĩa là onItemSelected () không bao giờ được gọi.

Do đó, tôi đã thêm một câu lệnh if ngắn để kiểm tra mức độ Api:

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {

            if(Build.VERSION.SDK_INT >= 28){ //onItemSelected() doesn't seem to be called when listener is set on Api 28+
                check = 1;
            }

            if(++check > 1) {
                //Do your action here
            }
        }

Tôi nghĩ điều đó khá kỳ lạ và tôi không chắc người khác cũng gặp phải vấn đề này, nhưng trong trường hợp của tôi, nó đã hoạt động tốt.


0

Tôi đã đặt TextView lên trên Spinner, cùng kích thước và nền với Spinner, để tôi có quyền kiểm soát nhiều hơn đối với giao diện trước khi người dùng nhấp vào nó. Với TextView ở đó, tôi cũng có thể sử dụng TextView để gắn cờ khi người dùng đã bắt đầu tương tác.

Mã Kotlin của tôi trông giống như thế này:

private var mySpinnerHasBeenTapped = false

private fun initializeMySpinner() {

    my_hint_text_view.setOnClickListener {
        mySpinnerHasBeenTapped = true //turn flag to true
        my_spinner.performClick() //call spinner click
    }

    //Basic spinner setup stuff
    val myList = listOf("Leonardo", "Michelangelo", "Rafael", "Donatello")
    val dataAdapter: ArrayAdapter<String> = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, myList)
    my_spinner.adapter = dataAdapter

    my_spinner.onItemSelectedListener = object : OnItemSelectedListener {

        override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {

            if (mySpinnerHasBeenTapped) { //code below will only run after the user has clicked
                my_hint_text_view.visibility = View.GONE //once an item has been selected, hide the textView
                //Perform action here
            }
        }

        override fun onNothingSelected(parent: AdapterView<*>?) {
            //Do nothing
        }
    }
}

Tệp bố cục trông giống như thế này, với phần quan trọng là Spinner và TextView có cùng chiều rộng, chiều cao và lề:

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Spinner
                android:id="@+id/my_spinner"
                android:layout_width="match_parent"
                android:layout_height="35dp"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true" />

            <TextView
                android:id="@+id/my_hint_text_view"
                android:layout_width="match_parent"
                android:layout_height="35dp"                
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true"
                android:gravity="center_vertical"
                android:text="*Select A Turtle"
                android:textColor="@color/green_ooze"
                android:textSize="16sp" />

        </FrameLayout>

Tôi chắc chắn rằng các giải pháp khác hoạt động khi bạn bỏ qua cuộc gọi onItemSelected đầu tiên, nhưng tôi thực sự không thích ý tưởng giả định rằng nó sẽ luôn được gọi.

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.