Android Spinner: รับกิจกรรมการเปลี่ยนแปลงรายการที่เลือก


407

คุณจะตั้งค่าฟังเหตุการณ์สำหรับสปินเนอร์ได้อย่างไรเมื่อรายการที่เลือกเปลี่ยนแปลง

โดยพื้นฐานสิ่งที่ฉันพยายามทำคือสิ่งที่คล้ายกับสิ่งนี้:

spinner1.onSelectionChange = handleSelectionChange;

void handleSelectionChange(Object sender){
    //handle event
}

ฉันลองคำตอบเหล่านี้แล้ว แต่ไม่มีใครช่วยได้ เมื่อส่วนประกอบสปินเนอร์ไม่สนับสนุนกิจกรรมการคลิกรายการ เอกสารประกอบสปินเนอร์

คำตอบ:


812

คำตอบก่อนหน้านี้บางส่วนไม่ถูกต้อง มันทำงานกับวิดเจ็ตและมุมมองอื่น ๆ แต่เอกสารสำหรับวิดเจ็ตสปินเนอร์ระบุไว้อย่างชัดเจน:

สปินเนอร์ไม่สนับสนุนกิจกรรมการคลิกไอเท็ม การเรียกวิธีนี้จะทำให้เกิดข้อยกเว้น

ควรใช้OnItemSelectedListener ()แทน:

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }

});

มันใช้งานได้สำหรับฉัน

โปรดทราบว่าเมธอด onItemSelected จะถูกเรียกใช้เมื่อมุมมองกำลังถูกสร้างดังนั้นคุณสามารถพิจารณาวางไว้ในonCreate()การเรียกเมธอด


47
ปัญหาเกี่ยวกับสิ่งนี้คือเมธอด onItemSelected ยังถูกเรียกใช้เมื่อมุมมองกำลังถูกสร้าง ดังนั้นโค้ดที่เขียนในนั้นก็จะถูกประมวลผลเมื่อเริ่มต้นเช่นกัน มีวิธีการดำเนินการรหัสที่มีเฉพาะในกรณีที่มีการเลือกรายการจริงเรียกโดยผู้ใช้หรือไม่
Kennethvr

39
ที่จริงแล้วปัญหาสามารถแก้ไขได้โดยการกำหนด setOnItemSelectedListener ในการแทนที่ OnStart วิธีการและไม่ได้อยู่ในวิธีการ onCreate โง่ฉัน ...
Kennethvr

16
ฉันใส่ตัวฟังในเมธอด onStart แต่มันถูกเรียกก่อนที่ผู้ใช้จะได้เห็นอะไรเช่น onCreate คือดังนั้นในกรณีของฉันที่มีปุ่ม "ดำเนินการ" ที่จะมองไม่เห็นจนกว่าผู้ใช้จะเลือกบางสิ่ง ปุ่มจะปรากฏให้เห็นเมื่อแสดงผลเริ่มต้น คุณกำลังบอกว่าประสบการณ์ของคุณแตกต่างกันอย่างไร ถ้าเป็นเช่นนั้นคุณกำลังทำอะไรแตกต่างกันไปในวิธี onStart ที่ฉันหายไป?
Yevgeny Simkin

7
ใช้ฟิลด์อื่นภายในผู้ฟังที่ไม่ระบุชื่อของคุณเพื่อบันทึกการเลือกแรกและแจ้งให้ itItSelected ไม่ต้องทำอะไรนอกจากจะมีการเลือกเกิดขึ้น? แค่ความคิด
Sam Svenbjorgchristiensensen

4
แต่ถ้าผู้ใช้เลือกรายการ "เริ่มต้น" รายการนั้นจะอยู่ด้านบนสุด จากนั้นonItemSelected(...)ไม่โดน (ฉันรู้เพราะฉันเพิ่งพบสิ่งนี้ยาก)
Andrew Wyld

55
Spinner spnLocale = (Spinner)findViewById(R.id.spnLocale);

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
        // Your code here
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

หมายเหตุ:จำสิ่งหนึ่ง

OnItemSelectedListenerเหตุการณ์สปินเนอร์จะทำงานสองครั้ง:

  1. การเริ่มต้นปินเนอร์
  2. ผู้ใช้เลือกด้วยตนเอง

ลองแยกความแตกต่างทั้งสองโดยใช้ตัวแปรธง


3
ของฉันถูกเรียกมาสองครั้งด้วย! ฉันไม่สามารถแยกแยะว่าคุณแยกแยะระหว่างคนทั้งสองได้อย่างไร?
MAC

18
เพียงตั้งค่าบูลีนระดับโลกเช่นบูลีน initialDisplay = true และจากนั้นใน onSelect ของคุณดูว่าจริงหรือไม่ถ้าไม่ทำอย่างอื่นที่คุณกำลังจะเลือก แต่ตั้งค่าสถานะเป็นเท็จในครั้งต่อไปที่มันถูกเรียก (เมื่อผู้ใช้เลือกจริง)
Yevgeny Simkin

คำอธิบายที่ดีที่สุดเกี่ยวกับการดำเนินการของ OnclickListener
Pankaj Kumar

6
โดยส่วนตัวแล้วฉันรู้สึกตกใจที่มีบางสิ่งที่เรียบง่าย - เช่นวิดเจ็ต UI พื้นฐาน - เป็นเรื่องยากมากที่จะติดตั้ง ... อย่างจริงจัง - มันจะยากแค่ไหนในการสร้างคุณสมบัติ ชั้นเรียนของตัวเอง ?? ฉันไม่ใช่แฟนของ Objective C แต่ฉันจะบอกว่าการติดตั้งวิดเจ็ต iOS ใช้เวลาประมาณ 1 / 10th ของเวลาใน Android
Bennett Von Bennett

4
ฉันก็เห็นด้วย สปินเนอร์เป็นหนึ่งในเครื่องมือที่ทำให้เมา มันยากมากที่จะรู้ว่าเมื่อป๊อปอัพหรือวางเปิดหรือปิด การเพิ่มกิจกรรมสำหรับสิ่งนี้เป็นเรื่องยากไหม วิธีแก้ไขปัญหาข้างต้นสามารถบอกคุณได้เมื่อรายการเปิดหรือปิด แต่มีสามปัญหา: (1) ไม่มีเหตุการณ์สำหรับการเลือกรายการที่เลือกไว้แล้ว (และรายการปิด) และ (2) ไม่มีเหตุการณ์สำหรับยกเลิก (สัมผัส ปิดรายการเพื่อปิด) และ (3) onNothingSelected ดูเหมือนจะไม่ยิงฉัน
Batdude

19

คุณสามารถนำAdapterView.OnItemSelectedListenerคลาสมาใช้ในกิจกรรมของคุณ

จากนั้นใช้บรรทัดด้านล่างภายใน onCreate()

Spinner spin = (Spinner) findViewById(R.id.spinner);
spin.setOnItemSelectedListener(this);

จากนั้นแทนที่ทั้งสองวิธี:

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    selection.setText(items[position]);
}

public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
}

16

https://stackoverflow.com/q/1714426/811625

คุณสามารถหลีกเลี่ยงการ OnItemSelectedListener () ที่ถูกเรียกด้วยการตรวจสอบง่าย: เก็บดัชนีการเลือกปัจจุบันในตัวแปรจำนวนเต็มและตรวจสอบภายใน onItemSelected (.. ) ก่อนที่จะทำอะไร

เช่น:

Spinner spnLocale;

spnLocale = (Spinner)findViewById(R.id.spnLocale);

int iCurrentSelection = spnLocale.getSelectedItemPosition();

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
    if (iCurrentSelection != i){
            // Your code here
    }
    iCurrentSelection = i;
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

สาเหตุที่iCurrentSelectionควรอยู่ในขอบเขตวัตถุสำหรับการทำงาน!


1
คุณไม่สามารถใช้ตัวแปรที่ไม่ได้อยู่ในคลาสภายในที่ไม่ระบุชื่อ หากiCurrentSelectionประกาศตัวแปรภายในคลาสนิรนามนี้มันจะทำงานได้ดี คุณสามารถกำหนดค่าเริ่มต้นเป็น -1 เพื่อให้โค้ดถูกเรียกใช้ในการโทรครั้งแรก
dahvyd

2
@dahvyd นั้นถูกต้องหากคุณใช้สิ่งนี้ int ต้องเป็นที่สุด ไม่ว่าในกรณีใดมันใช้งานได้ดีจริงๆ ฉันกำลังปิดใช้งานเขตข้อมูล EditText หากไม่ได้เลือกตำแหน่ง 0 ไว้และหากมีการเปลี่ยนแปลงให้เปิดใช้งานอีกครั้ง ขอบคุณสำหรับสิ่งนี้.
natur3

8

ค้นหาชื่อสปินเนอร์ของคุณและค้นหา id จากนั้นใช้วิธีนี้

spinnername.setOnItemSelectedListener(new OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }
});

8

มันไม่สำคัญว่าคุณจะตั้ง OnItemSelectedListener ใน onCreate หรือ onStart มันจะยังคงถูกเรียกในระหว่างการสร้างกิจกรรมหรือเริ่ม (ตามลำดับ)
ดังนั้นเราสามารถตั้งค่าใน onCreate (และไม่ได้อยู่ใน onStart!)
เพียงเพิ่มแฟล็กเพื่อคิดการเริ่มต้นครั้งแรก:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

จากนั้นใน onCreate (หรือ onCreateView) เพียง:

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                if (!mSpinnerInitialized) {
                    mSpinnerInitialized = true;
                    return;
                }

                // do stuff
            }

            public void onNothingSelected(AdapterView<?> adapterView) {
                return;
            }
        });

1
ขอบคุณที่ใช้ธงนี้
Javan R.

7

เอกสารสำหรับเครื่องมือสปินเนอร์พูดว่า

สปินเนอร์ไม่สนับสนุนกิจกรรมการคลิกไอเท็ม

คุณควรใช้setOnItemSelectedListenerเพื่อจัดการปัญหาของคุณ


6
spinner1.setOnItemSelectedListener(
    new AdapterView.OnItemSelectedListener() {
        //add some code here
    }
);

1
สิ่งนี้ไม่ได้แก้ไขปัญหาของการโทรกลับนี้ถูกเรียกเมื่อมีการเริ่มต้นสปินเนอร์
Yevgeny Simkin

4

ใช้ตัวแปรโกลบอลสำหรับการเลือกสปินเนอร์ปัจจุบัน:

int currentItem = 0;

spinner_counter = (Spinner)findViewById(R.id.spinner_counter);
String[] value={"20","40","60","80","100","All"};
aa=new ArrayAdapter<String>(this,R.layout.spinner_item_profile,value);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_counter.setAdapter(aa);

spinner_counter.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(currentItem == position){
                return; //do nothing
            }
            else
            {
                 TextView spinner_item_text = (TextView) view;
                 //write your code here
            }
            currentItem = position;
        }

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

        }
    });

//R.layout.spinner_item_profile
<?xml version="1.0" encoding="utf-8"?>

<TextView  android:id="@+id/spinner_item_text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" 
android:layout_height="wrap_content"
android:background="@drawable/border_close_profile"
android:gravity="start"  
android:textColor="@color/black"         
android:paddingLeft="5dip"
android:paddingStart="5dip"
android:paddingTop="12dip"
android:paddingBottom="12dip"
/>

//drawable/border_close_profile
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
   <shape android:shape="rectangle">
    <solid android:color="#e2e3d7" />
   </shape>
 </item>
<item android:left="1dp"
android:right="1dp"
android:top="1dp"
android:bottom="1dp">
<shape android:shape="rectangle">
    <solid android:color="@color/white_text" />
</shape>
</item>
</layer-list>

4

ถ้าคุณต้องการจริง onChangedListener () เก็บค่าเริ่มต้นในตัวจัดการและตรวจสอบเพื่อดูว่ามีการเปลี่ยนแปลง มันง่ายและไม่ต้องใช้ตัวแปรทั่วโลก ใช้งานได้หากคุณมีสปินเนอร์มากกว่าหนึ่งหน้า

String initialValue = // get from Database or your object
mySpinner.setOnItemSelectedListener(new SpinnerSelectedListener(initialValue));

...

protected class SpinnerSelectedListener implements AdapterView.OnItemSelectedListener {

        private SpinnerSelectedListener() {
            super();
        }

        public SpinnerSelectedListener(String initialValue) {
            this();
            this.initialValue = initialValue;
        }

        private String initialValue;

        // getter and setter removed.  

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            final String newValue = (String) spinHeight.getItemAtPosition(position);
            if (newValue.equals(initialValue) == false) {
               // Add your code here.  The spinner has changed value. 

               // Maybe useful.   
               // initialValue = newValue;
            }

        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
               // Maybe useful.   
               // initialValue = null; 
        }
    }

วัตถุคือเพื่อนของคุณใช้พวกเขา


3
spinner.setOnItemSelectedListener(
            new AdapterView.OnItemSelectedListener() {

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

                    // TODO Auto-generated method stub
                }

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

                }
                //add some code here
            }
        );

1

วิธีนี้จะทำให้การทำงานของปินเนอร์และการค้นหาดูดีขึ้นและใช้สิ่งนี้ได้

    Spinner schemeStatusSpinner;

  schemeStatusSpinner = (Spinner) dialog.findViewById(R.id.spinner);

schemeStatusSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            // your code here
            if(schemeStatusSpinner.getSelectedItemId()==4){
                reasonll.setVisibility(View.VISIBLE);
            }
            else {
                reasonll.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) {
            // your code here
        }

    });

1

วิธีที่ดีที่สุดในสิ่งที่ผมคิดว่าจะเป็นที่จะมีในflagitemselected = 0; onCreate()และในรายการที่เพิ่มขึ้นของเหตุการณ์ที่เลือกเช่นธงflagitemselected++; จากนั้นตรวจสอบ

if(flagitemselected!=1)
{
// do your work here
}

นี่จะช่วยฉันเดา


0

หนึ่งในเคล็ดลับที่ฉันพบคือการใส่ setOnItemSelectedListeners ของคุณใน onWindowFocusChanged แทน onCreate ฉันยังไม่พบผลข้างเคียงที่ไม่ดีใด ๆ จากการทำเช่นนี้ โดยพื้นฐานแล้วให้ตั้งค่าผู้ฟังหลังจากหน้าต่างถูกดึง ฉันไม่แน่ใจว่าบ่อยแค่ไหนในการทำงานของ Windows FocusCanged แต่มันง่ายพอที่จะสร้างตัวแปรล็อคตัวเองได้หากคุณพบว่ามันทำงานบ่อยเกินไป

ฉันคิดว่า Android อาจใช้ระบบประมวลผลข้อความและถ้าคุณใส่ทุกอย่างไว้ใน onCreate คุณอาจพบกับสถานการณ์ที่ตัวหมุนได้รับการเติมข้อมูลหลังจากที่วาดเสร็จแล้ว ดังนั้นผู้ฟังของคุณจะเริ่มต้นหลังจากที่คุณตั้งค่าตำแหน่งรายการ นี่คือการเดาที่มีการศึกษาแน่นอน แต่อย่าลังเลที่จะแก้ไขให้ถูกต้อง


0

โดยค่าเริ่มต้นคุณจะได้รับไอเท็มแรกของอาร์เรย์สปินเนอร์

value = spinner.getSelectedItem().toString();

เมื่อใดก็ตามที่คุณเลือกค่าในสปินเนอร์สิ่งนี้จะให้ค่าที่คุณเลือก

หากคุณต้องการตำแหน่งของรายการที่เลือกให้ทำเช่นนั้น

pos = spinner.getSelectedItemPosition();

ทั้งสองคำตอบข้างต้นมีไว้สำหรับโดยไม่ใช้ฟัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.