2011-11-02 16 views
20

एंड्रॉइड स्पिनर के आसपास अपना सिर लेने में मुझे थोड़ी देर लग गई है। कई विफल कार्यान्वयन प्रयासों के बाद, और कई प्रश्नों को आंशिक रूप से मेरे खुद के समान पढ़ने के बाद, लेकिन without satisfactory answers, और कुछ बिना किसी उत्तर के, उदाहरण के लिए here और here, मुझे अंत में यह पता चला है कि एंड्रॉइड में "स्पिनर" डेस्कटॉप ऐप्स से "ड्रॉप-डाउन सूची" या HTML में एक चयन के समान नहीं है। हालांकि, मेरा ऐप क्या है (और मैं उन सभी अन्य पोस्टर्स के ऐप्स का अनुमान लगा रहा हूं जिनके प्रश्न समान हैं) जरूरत कुछ ऐसा है जो एक स्पिनर की तरह ड्रॉप-डाउन बॉक्स की तरह काम करता है।एंड्रॉइड स्पिनर का उपयोग कैसे करें ड्रॉप-डाउन सूची

मेरे दोनों समस्याओं क्या मैं पहली बार idiosynchrasies होने की OnItemSelectedListener माना के साथ कर रहे हैं (मैं इस साइट पर अलग सवाल के रूप में इन देखा है लेकिन नहीं एक के रूप में):

  1. पहली सूची आइटम की प्रारंभिक चयन उपयोगकर्ता की बातचीत के बिना स्वचालित रूप से ट्रिगर किया जाता है।
  2. जब आइटम पहले से चुना गया था तो उपयोगकर्ता द्वारा फिर से चुना जाता है, इसे अनदेखा किया जाता है।

अब मुझे लगता है कि, जब आप इसके बारे में सोचते हैं, यह है कि यह एक स्पिनर पर होने के लिए समझ में आता है - यह चयनित एक डिफ़ॉल्ट मान के साथ शुरू करने के लिए है, और आप यह केवल उस मान बदलने के लिए स्पिन, एक मान को फिर से चयन न करें - the documentation वास्तव में कहता है: "यह कॉलबैक केवल तभी लागू होता है जब नई चयनित स्थिति पहले चयनित स्थिति से अलग होती है"। और मैंने पहले स्वचालित चयन को अनदेखा करने के लिए answers suggesting that you set up a flag देखा है - मुझे लगता है कि अगर कोई दूसरा रास्ता नहीं है तो मैं इसके साथ रह सकता हूं।

लेकिन चूंकि मैं क्या वास्तव में चाहते हैं एक ड्रॉप-डाउन सूची है जो एक ड्रॉप-डाउन सूची के रूप में व्यवहार है चाहिए (और के रूप में उपयोगकर्ताओं और उम्मीद करनी चाहिए सकता है), मैं क्या जरूरत है कुछ एक स्पिनर कि एक बूंद की तरह बर्ताव की तरह है एक कॉम्बो-बॉक्स की तरह -डाउन। मुझे किसी भी स्वचालित प्री-चयन (जो मेरे श्रोता को ट्रिगर किए बिना होना चाहिए) के बारे में परवाह नहीं है, और मैं प्रत्येक चयन के बारे में जानना चाहता हूं, भले ही यह पहले जैसा ही हो (भले ही उपयोगकर्ता चयनित एक ही आइटम फिर से)।

तो ... क्या एंड्रॉइड में ऐसा कुछ है जो ऐसा कर सकता है, या स्पिनर को ड्रॉप-डाउन सूची की तरह व्यवहार करने के लिए कुछ कामकाज है? यदि इस साइट पर इस तरह का एक प्रश्न है जो मुझे नहीं मिला है, और जिसके पास संतोषजनक उत्तर है, तो कृपया मुझे बताएं (जिस स्थिति में मैं ईमानदारी से प्रश्न दोहराने के लिए क्षमा चाहता हूं)।

उत्तर

7

डेविड के जवाब में +1।

@Override 
void setSelectionInt(int position, boolean animate) { 
    mOldSelectedPosition = INVALID_POSITION; 
    super.setSelectionInt(position, animate); 
} 

इस तरह आप माता-पिता विधि चाल होगी: हालांकि, यहां एक कार्यान्वयन सुझाव है कि स्रोत से कॉपी-पेस्ट कोड शामिल नहीं करता है (जो, वैसे, वास्तव में डेविड के रूप में ही लग रहा है तैनात in 2.3 as well) है यह सोचने में कि यह हर बार एक नई स्थिति है।

वैकल्पिक रूप से, आप जब स्पिनर क्लिक किया जाता है अमान्य स्थिति की स्थापना और onNothingSelected में इसे वापस सेट कर सकते हैं। यह उतना अच्छा नहीं है, क्योंकि उपयोगकर्ता नहीं देख पाएगा कि संवाद कब होता है।

+0

हां, कक्षा को विस्तारित करना निश्चित रूप से जाने का तरीका है। चालाक कार्यान्वयन, बीटीडब्ल्यू। – davidcesarino

+1

धन्यवाद फेलिक्स, मेरे द्वारा +1। चयन को बदलने के आपके विचार ने मुझे एक ऐसे विकल्प के साथ आने में मदद की जो मेरी दोनों समस्याओं को हल करता है (स्वचालित प्रारंभिक चयन को भी रोकता है)। चूंकि मेरा समाधान केवल एक अधिक विशिष्ट उपयोग के मामले के लिए हो सकता है, हालांकि (और जब से मैं अजीब नहीं होना चाहता हूं और अपना खुद का उत्तर स्वीकार करता हूं जो आपके आधार पर है), मुझे आपको टिक देने में खुशी है। चीयर्स! माईस्पिनर में –

+1

मैंने पुराने चयन को रीसेट करने के लिए निम्नलिखित का प्रयास किया लेकिन यह काम नहीं करता है। @ ओवरराइड सार्वजनिक शून्य सेट चयन (int स्थिति) {super.set चयन (INVALID_POSITION); super.setSelection (स्थिति); } –

4

देखो। मैं अगर यह आपकी मदद करेंगे पता नहीं है, लेकिन जब से तुम ज्यादा सफलता के बिना एक जवाब की तलाश में थक लगते हैं, इस विचार को मदद मिल सकती है आप, कौन जानता है ...

Spinner वर्ग AbsSpinner से ली गई है।

void setSelectionInt(int position, boolean animate) { 
     if (position != mOldSelectedPosition) { 
      mBlockLayoutRequests = true; 
      int delta = position - mSelectedPosition; 
      setNextSelectedPositionInt(position); 
      layout(delta, animate); 
      mBlockLayoutRequests = false; 
     } 
    } 

यह AFAIK 1.5 source से लिया जाता है: इस के अंदर, वहाँ इस विधि है। शायद आप उस स्रोत को देख सकते हैं, देखें कि स्पिनर/एब्सस्पिनर कैसे काम करता है, और शायद उस वर्ग को उचित विधि को पकड़ने के लिए पर्याप्त है और जांचें कि position != mOldSelectedPosition है या नहीं।

मेरा मतलब है ... यह बहुत "ifs" (एंड्रॉइड वर्जनिंग दिमाग इत्यादि) के साथ "विशाल" हो सकता है, लेकिन चूंकि आप निराश लगते हैं (और मैं कई बार एंड्रॉइड के साथ रहा हूं) शायद यह आपको कुछ "प्रकाश" दे सकता है। और मुझे लगता है कि आपके पिछले शोध को देखकर कोई अन्य स्पष्ट उत्तर नहीं हैं।

मैं आपको शुभकामनाएं देता हूं!

+0

धन्यवाद, डेविड, मैं निश्चित रूप से उस पर एक नजर रखूंगा। मुझे पहले एंड्रॉइड स्रोत डाउनलोड करना होगा (एंड्रॉइड के लिए अपेक्षाकृत नया, जैसा कि आप बता सकते हैं ;-)। निराशाजनक बिट के बारे में स्पॉट करें, कुछ चीजें सिर्फ काम नहीं करतीं क्योंकि मैंने सोचा था, दूसरी बार जो चीजें जटिल लगती हैं, काम करते हैं, लेकिन मुझे लगता है कि यह हमेशा ऐसा होता है जब आपको एक नई एपीआई के बारे में सीखना होता है। –

+1

आप अंदरूनी ग्रहण से स्रोत ब्राउज़ भी कर सकते हैं। Http://www.vogella.de/articles/AndroidSourceCode/article.html#eclipsesource देखें जो आपके प्रयास को निश्चित रूप से आसान बना देगा। – davidcesarino

+0

चीयर्स फिर से, डेविड। बहुत उपयोगी लगता है। मैं भी आपकी पोस्ट को वोट दूंगा, लेकिन उसमें अभी तक प्रतिष्ठा की आवश्यकता नहीं है ;-) –

5

ठीक है, मुझे लगता है कि मैं डेविड और फेलिक्स के उत्तर दोनों की मदद से अपनी स्थिति के लिए एक समाधान के साथ आया हूं (मुझे विश्वास है कि डेविड ने फेलिक्स की मदद की है, जिसने बदले में मेरी मदद की)। मैंने सोचा कि अगर मैं किसी और को यह दृष्टिकोण उपयोगी भी पाता हूं तो मैं इसे कोड नमूना के साथ यहां पोस्ट कर दूंगा। यह मेरी दोनों समस्याओं को भी हल करता है (अवांछित स्वचालित चयन और वांछित पुनः चयन ट्रिगर दोनों)।

मैंने क्या किया गया है जोड़ा जाता है पहली बार एक आइटम के रूप में डमी आइटम मेरी सूची में "कृपया चुनें" (शुरू में सिर्फ स्वत: चयन समस्या को हल पाने के लिए इतना है कि मैं उपेक्षा कर सकता है जब यह उपयोगकर्ता को बताए बिना चयनित किया गया था) , और फिर, अन्य आइटम का चयन किया गया है और मैंने चयन को संभाला है, मैं बस रीसेट स्पिनर को डमी आइटम (जिसे अनदेखा किया जाता है) को रीसेट कर दिया गया है। इसके बारे में सोचने के लिए आओ, मुझे इस साइट पर अपना प्रश्न पोस्ट करने का निर्णय लेने से पहले इस बारे में बहुत पहले सोचना चाहिए था, लेकिन चीजें हमेशा अंधेरे में अधिक स्पष्ट होती हैं ... और मैंने पाया कि मेरे प्रश्न लिखने से वास्तव में मुझे इस बारे में सोचने में मदद मिली मैं हासिल करना चाहता था।

जाहिर है, यदि डमी आइटम होने से आपकी स्थिति में फिट नहीं हो पाता है, तो यह आपके लिए आदर्श समाधान नहीं हो सकता है, लेकिन जब से मैं चाहता था कि कोई कार्य चुनने के बाद उपयोगकर्ता ने एक मूल्य को ट्रिगर करना था (और मूल्य बना रहता है मेरे विशिष्ट मामले में चयनित नहीं है), यह ठीक काम करता है। मैं एक सरलीकृत कोड उदाहरण जोड़ने की कोशिश करूंगा (जैसा कि संकलित नहीं हो सकता है, मैंने अपने कामकाजी कोड से कुछ बिट्स निकाल दिए हैं और पेस्ट करने से पहले चीजों का नाम बदल दिया है, लेकिन उम्मीद है कि आपको नीचे विचार मिलेगा)।

सबसे पहले, सूची गतिविधि (मेरे मामले में) स्पिनर युक्त, चलो यह MyListActivity कॉल:

public class MyListActivity extends ListActivity { 

    private Spinner mySpinner; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // TODO: other code as required... 

     mySpinner = (Spinner) findViewById(R.id.mySpinner); 
     mySpinner.setAdapter(new MySpinnerAdapter(this)); 
     mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 
      @Override 
      public void onItemSelected(AdapterView<?> aParentView, 
         View aView, int aPosition, long anId) { 
       if (aPosition == 0) { 
        Log.d(getClass().getName(), "Ignoring selection of dummy list item..."); 
       } else { 
        Log.d(getClass().getName(), "Handling selection of actual list item..."); 
        // TODO: insert code to handle selection 
        resetSelection(); 
       } 
      } 

      @Override 
      public void onNothingSelected(AdapterView<?> anAdapterView) { 
       // do nothing 
      } 
     }); 
    } 

    /** 
    * Reset the filter spinner selection to 0 - which is ignored in 
    * onItemSelected() - so that a subsequent selection of another item is 
    * triggered, regardless of whether it's the same item that was selected 
    * previously. 
    */ 
    protected void resetSelection() { 
     Log.d(getClass().getName(), "Resetting selection to 0 (i.e. 'please select' item)."); 
     mySpinner.setSelection(0); 
    } 
} 

और स्पिनर एडाप्टर कोड इस (तरह कुछ दिखाई दे सकता है वास्तव में में एक आंतरिक वर्ग हो सकता है सूची गतिविधि यदि आप पसंद करते हैं) के ऊपर:

public class MySpinnerAdapter extends BaseAdapter implements SpinnerAdapter { 

    private List<MyListItem> items; // replace MyListItem with your model object type 
    private Context context; 

    public MySpinnerAdapter(Context aContext) { 
     context = aContext; 
     items = new ArrayList<MyListItem>(); 
     items.add(null); // add first dummy item - selection of this will be ignored 
     // TODO: add other items; 
    } 

    @Override 
    public int getCount() { 
     return items.size(); 
    } 

    @Override 
    public Object getItem(int aPosition) { 
     return items.get(aPosition); 
    } 

    @Override 
    public long getItemId(int aPosition) { 
     return aPosition; 
    } 

    @Override 
    public View getView(int aPosition, View aView, ViewGroup aParent) { 
     TextView text = new TextView(context); 
     if (aPosition == 0) { 
      text.setText("-- Please select --"); // text for first dummy item 
     } else { 
      text.setText(items.get(aPosition).toString()); 
      // or use whatever model attribute you'd like displayed instead of toString() 
     } 
     return text; 
    } 
} 

मुझे लगता है कि (इस की कोशिश की है नहीं) एक ही प्रभाव setSelected(false)setSelection(0) के बजाय का उपयोग कर प्राप्त किया जा सकता है, लेकिन फिर से स्थापित करने के लिए "कृपया" मेरे प्रयोजनों के ठीक सूट। और, "देखो, माँ, कोई ध्वज नहीं!" (हालांकि मुझे लगता है कि 0 चयनों को अनदेखा करना असंभव नहीं है।)

उम्मीद है कि यह किसी अन्य उपयोग के मामले में किसी और की मदद कर सकता है। :-) अन्य उपयोग मामलों के लिए, फ़ेलिक्स का उत्तर अधिक उपयुक्त हो सकता है (धन्यवाद फेलिक्स!)।

+0

यह सुनिश्चित नहीं है कि मुझे एक साल बाद इस आधा के लिए डाउनवोट क्यों मिला। डाउनवोट समझाते हुए एक टिप्पणी की सराहना की जाएगी। –

+0

और अगर पहली पंक्ति से छुटकारा पाने की जरूरत है, हम इस लाइनों getDropDownView विधि को जोड़ सकते हैं अगर (स्थिति == 0) { \t \t \t \t view.getLayoutParams() ऊंचाई = 1। \t \t \t} else { \t \t \t \t view.getLayoutParams() ऊंचाई = ViewGroup.LayoutParams.WRAP_CONTENT। \t \t \t} – deviant

2

स्पिनर को संशोधित करना उपयोगी है यदि आप एक ही गतिविधि में एक साथ एकाधिक चयन करना चाहते हैं। यदि आप केवल उपयोगकर्ता को पदानुक्रमित चयन करने की इच्छा रखते हैं, उदाहरण के लिए:

आप क्या खाना चाहते हैं?

फल

  • सेब
  • केले
  • संतरे

फास्ट फूड

  • बर्गर
  • आलू
  • हॉट डॉग,

तो ExpandableListView आपके लिए बेहतर हो सकता है। यह उपयोगकर्ता को विभिन्न समूहों के पदानुक्रम पर नेविगेट करने और बाल तत्व चुनने की अनुमति देता है। यह उपयोगकर्ता के लिए चुनने के लिए कई स्पिनरों के समान होगा - यदि आप एक साथ चयन की इच्छा नहीं रखते हैं, तो यह है।

0

मैंने इस धागे में उल्लिखित कई मुद्दों के माध्यम से काम किया, इससे पहले कि मुझे एहसास हुआ कि PopupMenu विजेट मैं वास्तव में चाहता था। स्पिनर की कार्यक्षमता को बदलने के लिए आवश्यक हैक्स और वर्कअराउंड के बिना इसे कार्यान्वित करना आसान था। पॉपअपमेनू अपेक्षाकृत नया था जब यह धागा 2011 में शुरू हुआ था, लेकिन मुझे आशा है कि इससे किसी को भी इसी तरह की कार्यक्षमता की तलाश करने में मदद मिलेगी।

+0

PopupMenu एक लगातार चयन – NewEndian

+0

नहीं रखता है यह एक चयनित आइटम स्थापित करने के लिए निर्मित संपत्ति है, लेकिन आप myPopupMenu.getMenu() के साथ चयन कर सकते हैं। GetItem (SelectedIndex) नहीं है .setChecked (सच)। – arlomedia

1

यहाँ किसी भी (इरादा या अनायास ही) कार्यक्रम संबंधी और उपयोगकर्ता द्वारा शुरू किए परिवर्तन के बीच अंतर करने के लिए कोई वैकल्पिक समाधान है:

दोनों एक OnTouchListener और OnItemSelectedListener

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) { 
      // Your selection handling code here 
      userSelect = false; 
     } 
    } 

} 

के रूप में स्पिनर के लिए अपने श्रोता बनाएं जोड़े स्पिनर को श्रोता दोनों घटना प्रकार के लिए पंजीकरण

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

इस मामले को संभाल नहीं होगा जो फिर से चयन में उपयोगकर्ता द्वारा एक ही आइटम का आयन ITemSelected विधि (जिसे मैंने नहीं देखा है) को ट्रिगर नहीं करता है, लेकिन मुझे लगता है कि ऑन कोड को कुछ कोड जोड़कर संभाला जा सकता है।

वैसे भी, एमोस की ओर इशारा करते हुए समस्याएं इस समाधान के बारे में सोचने से पहले मुझे पागल कर रही थीं, इसलिए मैंने सोचा कि मैं जितना संभव हो उतना व्यापक रूप से साझा करूंगा। इस पर चर्चा करने वाले कई धागे हैं, लेकिन मैंने अभी तक एक और समाधान देखा है जो इस प्रकार है: https://stackoverflow.com/a/25070696/4556980

+0

मुझे वास्तव में यह जवाब पसंद है, धन्यवाद। मेरे पास एक इटैम सेलेक्टेड ब्लॉक में एक नेटवर्क अनुरोध किया गया था और जब भी स्पिनर श्रोता सेट किया गया था तब उपयोगकर्ता की डेटा योजना के माध्यम से चबा नहीं चाहता था – isuPatches

संबंधित मुद्दे