2010-01-11 20 views
8

हाय सभी,एंड्रॉयड ListView चुनाव समस्या

मैं निम्नलिखित लंबे प्रश्न के लिए खेद है ...

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

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

दूसरा - एक मेनू से, मैं एक नया LinearLayout बजाय एक है कि ListView (अलग आवेदन की स्क्रीन) शामिल प्रदर्शित कर सकते हैं। जब ऐसा होता है, तब भी मैं LinearLayout की ऑब्जेक्ट को संग्रहीत करता हूं जिसमें ListView शामिल है, क्योंकि मैं इसे स्क्रैच से बनाये बिना इसे फिर से प्रदर्शित करने में सक्षम होना चाहता हूं। समस्या यह है कि जब मैं ListView के साथ LinearLayout को फिर से अपमानित करता हूं, तो ListView की पंक्तियों में से कोई भी चयनित नहीं होता है, भले ही ListView के साथ LinearLayout स्क्रीन को छोड़कर "सीरेटिन पंक्ति" चुना गया हो।

लंबे पद के लिए फिर से खेद है।

धन्यवाद!

उत्तर

3
  1. यह वह डिफ़ॉल्ट और अपेक्षित व्यवहार है। इसके साथ छेड़छाड़ दृढ़ता से के खिलाफ सुझाव दिया गया है।
  2. यह 1 से कुछ हद तक चलता है। चयनित राज्य लगातार नहीं है। इसके बजाय, एक OnItemClickListener असाइन करें, और इसे चयनित आइटम की आईडी को कुछ चर में संग्रहीत करें। आप आइटम जब आप वापस आते फिर से चयन करने की आवश्यकता है, तो आप setSelection()
+0

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

+0

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

+0

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

0

उपयोग कर सकते हैं यह मदद करनी चाहिए:

private void setListviewSelection(final ListView list, final int pos) { 
    list.post(new Runnable() { 
     @Override 
     public void run() { 
      list.setSelection(pos); 
      View v = list.getChildAt(pos); 
      if (v != null) { 
       v.requestFocus(); 
      } 
     } 
    }); 
} 
+1

काम नहीं कर रहा है। विधि में प्रवेश करता है लेकिन कुछ भी नहीं होता –

1

मुझे लगता है कि इस मुद्दे को notifyDataSetChanged() ; के बाद एक संदेश भेजने और में setSelection(0) बुला समाधान कर लिया है मेरा हैंडल मैसेज फ़ंक्शन। यह बदसूरत लगता है, लेकिन एसडीके विचित्र रूप से व्यवहार करते समय मुझे कई बार मदद मिली।

5
private void setListviewSelection(final ListView list, final int pos) { 
list.post(new Runnable() 
    { 
    @Override 
    public void run() 
     { 
     list.setSelection(pos); 
     View v = list.getChildAt(pos); 
     if (v != null) 
     { 
      v.requestFocus(); 
     } 
    } 
}); 
} 

ऊपर सूची में ध्यान केंद्रित करने वाली पंक्ति सेट करने में मेरी सहायता करता है।

+2

हम्म यह सही नहीं है। 'सेट चयन' सूची के i-th तत्व का चयन करेगा, लेकिन 'getChildAt' रिटर्न * दृश्य * बच्चा i.e. यह वर्तमान स्क्रॉल पर निर्भर करता है। तो यदि सूची स्क्रॉल की गई है, तो यह काम नहीं करेगा। – smok

+0

@smok – Divers

19

हाँ, एक iOS डेवलपर के दृष्टिकोण से, मुझे लगता है कि यह जैसी सुविधाओं के लागू करने के लिए "सेट डिफ़ॉल्ट चयन जब शुरू करने" और "चयन स्थिति याद उपयोगकर्ता क्लिक किया पंक्ति के बाद" ListView के लिए बेहद मुश्किल है।

तो चलो से शुरू करते हैं "चयन को याद" first.The समस्या यह है कि भले ही आप जानते हैं कि आप को उजागर/दबाया/फोकस कि शैली style.But परिभाषित करने के लिए चयनकर्ता एक्सएमएल उपयोग कर सकते हैं उपयोगकर्ता के बाद रखा जाना नहीं जाएगा उस पंक्ति पर क्लिक किया।उदाहरण के लिए, मैं इस तरह एक हाइलाइटिंग चयनकर्ता एक्सएमएल (res/drawable फ़ोल्डर के अंतर्गत list_selector.xml) है (लेकिन आप अन्य क्षेत्रों पंक्ति में TextView के पाठ का रंग की तरह हाइलाइट करने के लिए हो सकता है):

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:drawable="@drawable/list_selector_pressed" android:state_pressed="true" /> 
    <item android:drawable="@drawable/list_selector_pressed" android:state_selected="true" /> 
</selector>  

और list_selector_pressed। एक्सएमएल जो हाइलाइटिंग शैली में परिभाषित किया गया - सेट पृष्ठभूमि रंग एक ग्रे रंग के लिए:

<?xml version="1.0" encoding="utf-8"?> 
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item> 
     <shape xmlns:android="http://schemas.android.com/apk/res/android"> 
      <solid android:color="@color/dark_gray" /> 
     </shape> 
    </item> 
</layer-list> 

तो @ दाऊद Hedlund के रूप में सुझाव:

बल्कि, एक OnItem आवंटित क्लिक लिस्टनर, और इसे चयनित आइटम की आईडी को कुछ चर में स्टोर कर दें।

private View currentSelectedView; 

तो

@Override 
public void onListItemClick(ListView l, View v, int position, long id) { 
    if (currentSelectedView != null && currentSelectedView != v) { 
     unhighlightCurrentRow(currentSelectedView); 
    } 

    currentSelectedView = v; 
    highlightCurrentRow(currentSelectedView); 
    //other codes 
    } 

सुंदर सरल करने के लिए जाना:

आप अपने वर्ग के शीर्ष पर एक उदाहरण चर बनाने के लिए की जरूरत है हम जाँच अगर currentSelectedView अशक्त या वर्तमान क्लिक किया दृश्य है या नहीं। हम पहली बार विधि unhighlightCurrentRow (currentSelectedView) को कॉल करके किसी भी शैली को हाइलाइट करने के लिए --- आप सोच सकते हैं कि हम तत्काल परिवर्तनीय वर्तमान क्यों देखते हैं पैरामीटर के रूप में चयनित, मैं इसे बाद में समझाऊंगा। फिर हम वर्तमान चयन दृश्य को देखते हैं और वर्तमान पंक्ति को हाइलाइट करते हैं; ताकि उपयोगकर्ता के क्लिक करने के बाद शैली जारी रहेगी।

private void unhighlightCurrentRow(View rowView) { 
    rowView.setBackgroundColor(Color.TRANSPARENT); 
    TextView textView = (TextView) rowView.findViewById(R.id.menuTitle); 
    textView.setTextColor(getResources().getColor(R.color.white)); 
} 

private void highlightCurrentRow(View rowView) { 
    rowView.setBackgroundColor(getResources().getColor(
      R.color.dark_gray)); 
    TextView textView = (TextView) rowView.findViewById(R.id.menuTitle); 
    textView.setTextColor(getResources().getColor(R.color.yellow)); 

} 

आह, यही है। इस प्रकार हम सूची दृश्य के लिए "चयन याद रखें" को कार्यान्वित करते हैं। जैसा कि आप देख, हम दोनों एक्सएमएल और जावा कोड में स्टाइलिंग के लिए कोड नकल करने के लिए है - बहुत बेवकूफ :(

के बारे में "सेट डिफ़ॉल्ट चयन" अगला आप सोच सकते आप कर सकते हैं कि इस

listView.setAdapter(adatper) 
listView.setSelection(0); 
currentSelectedView = listView.getChildAt(0); 
highlightCurrentRow(currentSelectedView); 
गतिविधि या onActivityCreated() में onCreate() में

टुकड़ा में।
लेकिन अगर आप इसे चलाने के लिए, आप NullPointer अपवाद और क्यों मिलेगा? क्योंकि इस समय, सूचीदृश्य अभी तक गाया नहीं है और एंड्रॉयड नहीं है आईओएस की तरह जो व्यूविलपियर है। इसलिए आपको यह याद रखने के लिए एक त्वरित चर बनाना है कि यह है या नहीं पहली बार सूचीदृश्य सेल रेंडर करने के लिए और onListItemClick में उस चर अनसेट करने के लिए:

private Boolean firstTimeStartup = true; 

तो विधियों को जोड़ने:

तो currentSelectedView घोषणा के तहत लगता है हम सूची दृश्य में पहली पंक्ति हाइलाइट करना चाहते हैं:

public class HomeAdapter extends ArrayAdapter<String> { 
    int layoutResourceId; 

    public HomeAdapter(Context context, int textViewResourceId, 
      ArrayList<String> objects) { 
     super(context, textViewResourceId, objects); 
     layoutResourceId = textViewResourceId; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
      convertView = LayoutInflater.from(getContext()).inflate(
        layoutResourceId, null); 
     } 

     if (firstTimeStartup && postion == 0) { 
      highlightCurrentRow(convertView); 
     } else { 
      unhighlightCurrentRow(convertView); 
     } 

     TextView title = (TextView) convertView 
       .findViewById(R.id.menuTitle); 
     title.setText(getItem(position)); 
     return convertView; 
    } 
} 

बहुत आसान।

@Override 
public void onListItemClick(ListView l, View v, int position, long id) { 

    if (firstTimeStartup) {// first time highlight first row 
     currentSelectedView = l.getChildAt(0); 
    } 
    firstTimeStartup = false; 
    if (currentSelectedView != null && currentSelectedView != v) { 
     unhighlightCurrentRow(currentSelectedView); 
    } 

    currentSelectedView = v; 
    highlightCurrentRow(currentSelectedView); 

    //other codes 
} 

ये लीजिए: लेकिन आप onListItemClick विधि में कुछ बदलाव करने की जरूरत है! एंड्रॉइड का आनंद लें :)

+0

के साथ सहमति दें कोड के याद/हाइलाइटिंग हिस्से के बारे में मेरा अनुभव यह था कि किसी को xml और प्रोग्रामेटिक सेटिंग्स दोनों को डुप्लिकेट करने की आवश्यकता नहीं है। ऐसा इसलिए है कि एक्सएमएल वाले लोग काम नहीं करते थे और प्रोग्रामिक रूप से लोग करते थे। उस अर्थ में, कोई 'list_selector.xml' और' list_selector_pressed.xml' के निर्माण को छोड़ सकता है और केवल उस कोड को लिखें जिसे आप – Thomas

0

मैं एडाप्टर का उपयोग कर रहा हूं और कस्टम पृष्ठभूमि रंग सेट नहीं करना चाहता था, लेकिन एंड्रॉइड का उपयोग करें: state_selected drawable xml में। SetSelection मेरे लिए काम नहीं करता है, लेकिन शायद यह भी है क्योंकि मुझे SetNotifyDataChanged की आवश्यकता है जो दर्शाता है कि चयनित राज्य लगातार नहीं है।

मैंने यह भी पाया कि ListView में किसी आइटम के लिए चयनित स्थिति लगातार नहीं है, क्योंकि SetNotifyDataChanged परिणाम सूची दृश्य लेआउट को अद्यतन करने में परिणाम देता है जो उन्हें साफ़ करता है। एडाप्टर के GetView में चयनित आइटम को सेट करना भी बहुत जल्द है।

आखिरकार मैंने चयनित आइटम के दृश्य के लिए चयनित स्थिति को सेटव्यू के लेआउट के बाद चयनित स्थिति को बदल दिया है, जो तब होता है जब लेआउट चेंज इवेंट ट्रिगर किया जा रहा है (जावा में यह शायद सूची दृश्य के ऑनलेआउट चेंजलिस्ट को जोड़ रहा है)।

इसे वास्तव में आसान बनाने के लिए मैं चयनित आइटम के दृश्य को एडाप्टर के चयनित इटिम व्यू के रूप में संग्रहीत करता हूं। ListView के लेआउट चेंज eventhandler में मैंने बस एडाप्टर के चयनित ItemView सेट किया है। सत्य पर चयन किया गया।

public class RingTonesListAdapter : BaseAdapter<RingToneItem> 
{ 
    List<RingTone> Items { get; set; } 

    public override View GetView(int position, View convertView, ViewGroup parent) 
    { 
     View view = convertView; 

     // re-use an existing view, if one is available 
     // otherwise create a new one 
     if (view == null) 
     { 
      view = Context.LayoutInflater.Inflate(Resource.Layout.AlertSoundItem, parent, false); 
      view.Click += SelectRingTone; 
     } 

     RingTone ringTone = this[position]; 
     if (ringTone.Selected) 
     { 
      //==> Important 
      //Store this view since it's the view for the Selected Item 
      SelectedItemView = view; 
      //Setting view.Selected to true here doesn't help either, since Selected will be cleared after. 
     } 

     return view; 
    } 

    private void SelectRingTone(object sender, EventArgs args) 
    { 
     View view = (View)sender; 
     string title = view.FindViewById<TextView>(Resource.Id.ringToneTitle).Text; 
     RingToneItem ringToneItem = Items.First(rt => rt.Title == title); 
     if (!ringToneItem.Selected) 
     { 
      //The RingTone was not selected and is selected now 
      //Deselect Old and Select new 
      foreach (RingToneItem oldItem in Items.Where(rt => rt.Selected)) 
      { 
       oldItem.Selected = false; 
      } 

      // Select New RingTone 
      ringToneItem.Selected = true; 
      //Update the ListView. 
      //This will result in removal of Selected state for all Items when the ListView updates it's layout 
      NotifyDataSetChanged(); 
     } 

     //Now play the test sound 
     NotifierService.TestSound(Context, ringToneItem); 
    } 

    public View SelectedItemView { get; set; } 
} 
:

यहाँ मेरी गतिविधि से कोड है, जहां मैं ListView के लिए एडाप्टर सेट करते हैं और LayoutChange की सदस्यता (या जावा में एक OnLayoutChangeListener देते हैं)

 ringTonesListView.Adapter = ringTonesListAdapter; 
     ringTonesListView.LayoutChange += (s, layoutChangeArgs) => { 
      //At this stage the layout has been updated and the Selected can be set to true for the view of the selected item. This will result in android:state_selected logic to be applied as desired and styling can be completely done per layout in Resources. 
      ringTonesListAdapter.SelectedItemView.Selected = true; 
     }; 

यहाँ एडाप्टर के लिए मेरे कोड है

1

मेरे लिए एक बहुत साफ समाधान इस तथ्य के आसपास केंद्रित है कि यदि आप या android:choiceMode="multipleChoice" को अपने ListView में सेट करते हैं, तो ListView चेक किए गए राज्य को या तो बनाए रखने का प्रयास करेगा इंजेल या एकाधिक चयन ListView। पकड़ लिया है कि यह सूची सेल Checkable

को लागू तो, आप एक CheckableLinearLayout (या FrameLayout बेहतर हो सकता है) को लागू करने से शुरू पर निर्भर करता है ताकि एंड्रॉयड आप के लिए जाँच की राज्य बनाए रखेंगे और आप सिंक में Drawable के रख सकते है। यहां कुंजी refreshDrawableState और onCreateDrawableState वे ड्रायबल अपडेट करें ताकि पृष्ठभूमि को हाइलाइट किया जा सके या नहीं।

public class CheckableLinearLayout extends LinearLayout implements Checkable { 
    boolean checked; 

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

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

    public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    @Override 
    public void setChecked(boolean checked) { 
     this.checked = checked; 
     refreshDrawableState(); 
    } 

    @Override 
    public boolean isChecked() { 
     return checked; 
    } 

    @Override 
    public void toggle() { 
     setChecked(!isChecked()); 
    } 

    private static final int[] CheckedStateSet = { android.R.attr.state_checked }; 

    @Override 
    protected int[] onCreateDrawableState(int extraSpace) { 
     final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
     if (isChecked()) { 
      mergeDrawableStates(drawableState, CheckedStateSet); 
     } 
     return drawableState; 
    } 
} 
फिर

, पृष्ठभूमि drawable कि जाँच की राज्य दिखाएगा के लिए एक सरल selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:drawable="#ccc" android:state_checked="true" /> 
    <item android:drawable="@android:color/transparent" /> 
</selector> 

अब मैं किसी भी सूची है कि मैं लगातार चयन राज्य (एकाधिक या एकल दिखाना चाहते हैं CheckableLinearLayout उपयोग कर सकते हैं):

<CheckableLinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="@drawable/checkable_cell" 
    > 

    <TextView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:id="@+id/text" 
     android:layout_margin="10dp" 
     android:maxLines="8" 
     /> 
</CheckableLinearLayout> 

मैं जाँच की स्थिति को अपडेट Fragment में किसी विशेष कोड की जरूरत नहीं है, और मैं चयनित बनाए रख सकते हैं साथ रोटेशन के आसपास स्थिति:

state.putInt("selection", listView.getCheckedItemPosition()); 

और

listView.setItemChecked(state.getInt("selection"), true); 

इसी तरह, मैं setItemChecked का उपयोग शुरू में चयनित आइटम सेट करें, या (एकाधिक चयन के लिए या getCheckedItemPositions()) getCheckedItemPosition का उपयोग वर्तमान चयन पाने के लिए कर सकते हैं।

+0

का उपयोग करते हैं, मेरे उपयोग के मामले में काम किया। धन्यवाद। – MCLLC

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