2016-08-03 25 views
0

Ich habe eine listview, die Radio-Schaltflächen dynamisch hinzugefügt werden. Aber es verhält sich sehr fehlerhaft. Die radio buttons werden nach dem Scrollen in verschiedenen Zeilen angezeigt, einige verschwinden usw. Ich habe den Adapter hier gepostet. Bitte geben Sie Ihre wertvollen Vorschläge dazu an.ListView mit RadioButtons Verhalten Buggy

public class CheckTentativePlanNSaveProductLoanEmiListAdapter extends ArrayAdapter<AddSanctionListRowDS> { 

    private final Activity mContext; 
    private final int mResource; 
    private final ArrayList<CheckTentativePlanNsaveListRowDs> mAddSanctionListRowDS; 
    private EditText mAddSanctionRowValueET; 
    private Calendar mMyCalendar; 
    private ArrayList<String> mProductDetailsScreenEnteredDetails; 


    public CheckTentativePlanNSaveProductLoanEmiListAdapter(Activity context, int resource, ArrayList<CheckTentativePlanNsaveListRowDs> iAddSanctionListRowObj, ArrayList<String> iAddSanctionEnteredValues) 
    { 
     super(context, resource); 

     this.mContext     = context; 
     this.mResource     = resource; 
     this.mAddSanctionListRowDS  = iAddSanctionListRowObj; 

     //This depicts the values when entered or changed... 
     this.mProductDetailsScreenEnteredDetails = iAddSanctionEnteredValues; 
    } 

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

    public View getView(final int position,View convertView,ViewGroup parent) { 

     SaveProductListViewHolder saveProductListViewHolderObj; 

     //View is creating... 
     if (convertView == null) { 

      convertView         = LayoutInflater.from(mContext).inflate(mResource, parent, false); 

      saveProductListViewHolderObj    = new SaveProductListViewHolder(); 
      saveProductListViewHolderObj.key_tv   = (TextView) convertView.findViewById(R.id.id_check_tentative_plan_n_save_product_non_loan_row_key_tv); 
      saveProductListViewHolderObj.value_et  = (EditText) convertView.findViewById(R.id.id_check_tentative_plan_n_save_product_non_loan_value_et); 
      LinearLayout etParentLl      = (LinearLayout) convertView.findViewById(R.id.id_check_tentative_plan_n_save_product_et_non_loan_rb_ll); 
      saveProductListViewHolderObj.et_parent_ll = etParentLl; 

      RadioGroup.OnCheckedChangeListener onCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() { 
       @Override 
       public void onCheckedChanged(RadioGroup group, int checkedId) { 

        for (int i = 0; i < ((LinearLayout) group.getParent()).getChildCount(); i++) { 
         RadioGroup sisterRadioGroup = (RadioGroup) ((LinearLayout) group.getParent()).getChildAt(i); 
         if (group != sisterRadioGroup) { 
          sisterRadioGroup.setOnCheckedChangeListener(null); 
          sisterRadioGroup.clearCheck(); 
          sisterRadioGroup.setOnCheckedChangeListener(this); 
         } 
        } 
       } 
      }; 

      final CheckTentativePlanNsaveListRowDs currentRowDsObj = mAddSanctionListRowDS.get(position); 


      if (currentRowDsObj.getmRadioBtnData().size() > 0) { 


       //Set layout width = fill parent 
       //Layout height = wrap content 
       //Orientation will be vertical 

       LinearLayout radioGrpParentLl      = new LinearLayout(mContext); 
       LinearLayout.LayoutParams paramsRadioGrpParentLl = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); 
       radioGrpParentLl.setLayoutParams(paramsRadioGrpParentLl); 
       radioGrpParentLl.setOrientation(LinearLayout.VERTICAL); 

       float halfOfRadioCount  = (float) currentRowDsObj.getmRadioBtnData().size()/2; 

       int noOfRadioGroupsNeeded = (int) Math.ceil(halfOfRadioCount); 

       for (int i = 0; i < noOfRadioGroupsNeeded; i++) { 

        final RadioGroup radioGroup = new RadioGroup(mContext); 
        RadioGroup.LayoutParams paramsRadio = new RadioGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
        radioGroup.setOrientation(RadioGroup.HORIZONTAL); 
        radioGroup.setLayoutParams(paramsRadio); 


        //Add 2 Radio Buttons... 

        //Left Radio Button... 

        RadioButton leftRadioButtonInCurrentRadioGroup = new RadioButton(mContext); 
        RadioGroup.LayoutParams paramsLeftRadioBtnInCurrentRadioGroup = new RadioGroup.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); 
        leftRadioButtonInCurrentRadioGroup.setLayoutParams(paramsLeftRadioBtnInCurrentRadioGroup); 
        paramsLeftRadioBtnInCurrentRadioGroup.weight = 1f; 
        leftRadioButtonInCurrentRadioGroup.setTypeface(Typeface.DEFAULT_BOLD); 
        leftRadioButtonInCurrentRadioGroup.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
         @Override 
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
          if (isChecked) { 
           //If checked, set the value... 
           int currentIndex = 0; 

           for (int i = 0; i < position; i++) { 
            if (currentRowDsObj.ismIsInputTypeNumeric() || currentRowDsObj.ismIsInputTypeText() || currentRowDsObj.ismIsDatePickerToBeShown()) { 
             currentIndex++; 
            } 

            if (currentRowDsObj.getmRadioBtnData().size() != 0) { 
             //A space allocated for unit... 
             currentIndex++; 
            } 
           } 

           if (currentRowDsObj.ismIsInputTypeText() || currentRowDsObj.ismIsInputTypeNumeric() || currentRowDsObj.ismIsDatePickerToBeShown()) { 
            //If current position has an allocation for entering value.. 
            //Increment a space for that as well.. 
            currentIndex++; 
           } 

           mProductDetailsScreenEnteredDetails.remove(currentIndex); 
           mProductDetailsScreenEnteredDetails.add(currentIndex, buttonView.getText().toString()); 
          } else { 
           //Do nothing.. 
          } 
         } 
        }); 

        String leftRadionBtnLabel = currentRowDsObj.getmRadioBtnData().get(2 * i).getLabel(); 
        leftRadioButtonInCurrentRadioGroup.setText(leftRadionBtnLabel); 
        radioGroup.addView(leftRadioButtonInCurrentRadioGroup); 

        if (((2 * i) + 1) < currentRowDsObj.getmRadioBtnData().size()) { 

         //At the end there is a chance that only one radio button has to be shown.. 
         //The above condition avoids trying to add.. 

         //Right Radio Button... 
         RadioButton rightRadioButtonInCurrentRadioGroup = new RadioButton(mContext); 
         RadioGroup.LayoutParams paramsRightRadioBtnInCurrentRadioGroup = new RadioGroup.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); 
         rightRadioButtonInCurrentRadioGroup.setLayoutParams(paramsLeftRadioBtnInCurrentRadioGroup); 
         paramsRightRadioBtnInCurrentRadioGroup.weight = 1f; 
         rightRadioButtonInCurrentRadioGroup.setTypeface(Typeface.DEFAULT_BOLD); 
         String rightRadioBtnLabel = currentRowDsObj.getmRadioBtnData().get((2 * i) + 1).getLabel(); 
         rightRadioButtonInCurrentRadioGroup.setText(rightRadioBtnLabel); 
         rightRadioButtonInCurrentRadioGroup.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
          @Override 
          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
           if (isChecked) { 
            //If checked, set the value... 
            int currentIndex = 0; 

            for (int i = 0; i < position; i++) { 
             if (currentRowDsObj.ismIsInputTypeNumeric() || currentRowDsObj.ismIsInputTypeText() || currentRowDsObj.ismIsDatePickerToBeShown()) { 
              currentIndex++; 
             } 

             if (currentRowDsObj.getmRadioBtnData().size() != 0) { 
              //A space allocated for unit... 
              currentIndex++; 
             } 
            } 

            if (currentRowDsObj.ismIsInputTypeText() || currentRowDsObj.ismIsInputTypeNumeric() || currentRowDsObj.ismIsDatePickerToBeShown()) { 
             //If current position has an allocation for entering value.. 
             //Increment a space for that as well.. 
             currentIndex++; 
            } 

            mProductDetailsScreenEnteredDetails.remove(currentIndex); 
            mProductDetailsScreenEnteredDetails.add(currentIndex, buttonView.getText().toString()); 
           } else { 
            //Do nothing.. 
           } 
          } 
         }); 

         radioGroup.addView(rightRadioButtonInCurrentRadioGroup); 
         radioGroup.setOnCheckedChangeListener(onCheckedChangeListener); 
        } 

        radioGrpParentLl.addView(radioGroup); 
       } 
       //Add RadioButton Group to the Parent Linear Layout.. 
       saveProductListViewHolderObj.et_parent_ll.addView(radioGrpParentLl); 
      } 

      convertView.setTag(saveProductListViewHolderObj); 


     }else{ 
      saveProductListViewHolderObj   = (SaveProductListViewHolder)convertView.getTag(); 
     } 

     final CheckTentativePlanNsaveListRowDs currentRowDsObj = mAddSanctionListRowDS.get(position); 

     saveProductListViewHolderObj.key_tv.setText(currentRowDsObj.getmEnterDetailsKey()); 
     saveProductListViewHolderObj.value_et.setHint(currentRowDsObj.getmEnterDetailsValue()); 
     saveProductListViewHolderObj.value_et.setFocusable(true); 


     //Based on the input type... 
     //Set the text change listener... 

     if(currentRowDsObj.ismIsInputTypeNumeric()){ 

      saveProductListViewHolderObj.value_et.setInputType(InputType.TYPE_CLASS_NUMBER); 

      saveProductListViewHolderObj.value_et.addTextChangedListener(new TextWatcher() { 
       @Override 
       public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

       } 

       @Override 
       public void onTextChanged(CharSequence s, int start, int before, int count) { 

       } 

       @Override 
       public void afterTextChanged(Editable s) { 
        int currentIndex = 0; 

        for(int i=0;i<position;i++){ 
         if(currentRowDsObj.ismIsInputTypeNumeric()||currentRowDsObj.ismIsInputTypeText()||currentRowDsObj.ismIsDatePickerToBeShown()) { 
          currentIndex++; 
         } 

         if(currentRowDsObj.getmRadioBtnData().size()!=0) { 
          //A space allocated for unit... 
          currentIndex++; 
         } 
        } 

        mProductDetailsScreenEnteredDetails.remove(currentIndex); 
        mProductDetailsScreenEnteredDetails.add(currentIndex,s.toString()); 

       } 
      }); 

     }else if(currentRowDsObj.ismIsInputTypeText()){ 

      saveProductListViewHolderObj.value_et.setInputType(InputType.TYPE_CLASS_TEXT); 

      saveProductListViewHolderObj.value_et.addTextChangedListener(new TextWatcher() { 
       @Override 
       public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

       } 

       @Override 
       public void onTextChanged(CharSequence s, int start, int before, int count) { 

       } 

       @Override 
       public void afterTextChanged(Editable s) { 
        int currentIndex = 0; 

        for(int i=0;i<position;i++){ 
         if(currentRowDsObj.ismIsInputTypeNumeric()||currentRowDsObj.ismIsInputTypeText()||currentRowDsObj.ismIsDatePickerToBeShown()) { 
          currentIndex++; 
         } 

         if(currentRowDsObj.getmRadioBtnData().size()!=0){ 
          //A space allocated for unit... 
          currentIndex++; 
         } 
        } 

        mProductDetailsScreenEnteredDetails.remove(currentIndex); 
        mProductDetailsScreenEnteredDetails.add(currentIndex,s.toString()); 
       } 
      }); 

     }else if(currentRowDsObj.ismIsDatePickerToBeShown()){ 

      //Here whether number or text... 
      //Doesnot matter... 
      saveProductListViewHolderObj.value_et.setInputType(InputType.TYPE_CLASS_NUMBER); 

      saveProductListViewHolderObj.value_et.addTextChangedListener(new TextWatcher() { 
       @Override 
       public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

       } 

       @Override 
       public void onTextChanged(CharSequence s, int start, int before, int count) { 

       } 

       @Override 
       public void afterTextChanged(Editable s) { 

        //Calculate position dynamically here... 

        int currentIndex = 0; 

        for(int i=0;i<position;i++){ 
         if(currentRowDsObj.ismIsInputTypeNumeric()||currentRowDsObj.ismIsInputTypeText()||currentRowDsObj.ismIsDatePickerToBeShown()) { 
          currentIndex++; 
         } 

         if(currentRowDsObj.getmRadioBtnData().size()!=0){ 
          //A space allocated for unit... 
          currentIndex++; 
         } 
        } 

        mProductDetailsScreenEnteredDetails.remove(currentIndex); 
        mProductDetailsScreenEnteredDetails.add(currentIndex,s.toString()); 

       } 
      }); 

     }else{ 
      saveProductListViewHolderObj.value_et.setVisibility(View.GONE); 
     } 

     return convertView; 

    } 

    static class SaveProductListViewHolder { 

     public TextView key_tv; 
     public EditText value_et; 
     public LinearLayout et_parent_ll; 

    } 
} 
+0

Diese 'getView'-Methode ist zu schwer zu folgen, wie es ist ... Ich empfehle dringend, einige Refactoring (vielleicht finden Sie den Fehler selbst dabei) –

+0

Die einzige Frage ist, wo sollte ich den Zusatz von dynamischen platzieren Radio Buttons zur Ansicht? Sollte das innerhalb der (convertView == null) oder außerhalb sein? –

Antwort

1

EDIT: Nun, da ich Ihren Code bin Parsen ein wenig tiefer, ich glaube, Sie haben ein noch größeres Problem, weil Sie dynamisch Radiogruppen zu Ihrem Listenelement hinzugefügt werden. Das dynamische Hinzufügen/Entfernen von Ansichten aus einem Listenelement wird Ihnen Kopfschmerzen bereiten.

Hier ist, was ich meine: Das Modell für die Liste Artikel ist currentRowDsObj, die Sie hier bekommen:

 final CheckTentativePlanNsaveListRowDs currentRowDsObj = 
       mAddSanctionListRowDS.get(position); 

Dann haben Sie etwas in Ihrem Modell, das wie viele Radiogruppen Sie gehen zu addieren bestimmt:

  float halfOfRadioCount = 
        (float) currentRowDsObj.getmRadioBtnData().size()/2; 

      int noOfRadioGroupsNeeded = 
        (int) Math.ceil(halfOfRadioCount); 

Also lassen Sie sich sagen, dass Ihr Listenelement an der Position 0 hat mRadioBtnData.size() == 4. Sie werden zwei Funkgruppen zu dem Listenelement hinzuzufügen.

Nehmen wir jetzt an, der Benutzer scrollt und sie erreichen die Position 10. Die Position 0 wurde vom Bildschirm gescrollt, so dass sie recycelt wird. Das Listenelement an Position 10 hat mRadioBtnData.size() == 6, also sollten Sie drei Funkgruppen haben. getView für Position 10 erhält die wiederverwertete Ansicht von Position 0. Ihre Recyclingansicht hat jedoch nur zwei Gruppen vom letzten Mal!

Sie werden viel härter darüber nachdenken müssen, wie Sie dies erreichen können. Hier sind ein paar Optionen:

  • Was ist die maximale Anzahl der Optionsfelder, die ein Element haben könnte? Wenn es nur 5 ist, könnten Sie fünf verschiedene Ansichtsarten haben. Sie können für jeden Objekttyp einen anderen Layouttyp verwenden. Dann überschreiben Sie getItemViewType(), um einen anderen Typwert basierend auf der Anzahl der Optionsfelder zurückzugeben, die Sie haben. Dies funktioniert folgendermaßen: Wenn die Listenansicht weiß, dass Position 0 und Position 10 einen Positionsansichtstyp == 2 aufweisen, wird für Position 10 aufgerufen und nur erhält eine wiederverwendbare Ansicht von Position 0 oder einer anderen Position mit dem gleichen Artikelansichtstyp. So können Sie sich darauf verlassen, dass die Recycling-Ansicht genau Ihren Vorstellungen entspricht.

  • Ich habe Code geschrieben, wo ich getChildCount() auf der Gruppe der wiederverwerteten Ansicht aufgerufen habe und wenn es weniger Ansichten als ich benötigt hatte, fügte ich sie hinzu. Wenn es mehr Ansichten hatte, als ich brauchte, entfernte ich die zusätzlichen. Das ist ziemlich hässlich und ich würde es nicht empfehlen.

Auch können Sie Ihre Logik vereinfachen, indem eine GridLayout mit oder FlowLayout so dass Sie nicht zählen müssen, wie viele Zeilen hinzufügen?

Ein weiterer Punkt ist, dass RadioGroup ist ein LinearLayout, so dass es alle Ihre Radiobuttons in einer einzigen Zeile oder Spalte sein soll. Da Sie über ein Raster mit Optionsfeldern verfügen, müssen Sie Ihre zuvor ausgewählten Schaltflächen möglicherweise selbst deaktivieren. Ich habe einen Code geschrieben, der das auch macht, wenn die Radioknöpfe selbst Listenelemente innerhalb einer RecyclerView waren.

Ich hoffe, dass einige davon geholfen haben.Überdenken Sie Ihr Design und machen Sie einen weiteren Schwung beim Code; Wenn Sie noch Hilfe benötigen, posten Sie eine weitere Frage.


Dies geschieht wegen View-Recycling.

Sie ändern die Listenelementansicht aus dem Ereignishandler, und das wird nie funktionieren.

Mit einem Adapter müssen Sie immer das Modell vom Controller (Ereignishandler) ändern und die Ansicht vom Modell (getView) aktualisieren.

Soweit ich das beurteilen kann, scheinen Sie keine Datenstruktur zu haben, die den Radio Button-Status modelliert, also müssen Sie das dem Adapter hinzufügen. Verwenden Sie diese Daten, um den überprüften Zustand der Ansicht in getView festzulegen, aktualisieren Sie dann die Daten von onCheckedChangedListener und rufen Sie notifyDataSetChanged auf dem Adapter auf.

In der Regel muss in einer Listenelementansicht, die sich ändern kann, eine Art von entsprechenden Modelldaten vorhanden sein.

+0

Jedes Code-Snippet wird eine große Hilfe sein. Mit dem Modellieren meinst du das Hinzufügen eines Optionsfelds zum Ansichtshalter? –

+0

Bei der Modellierung meine ich, dass ich eine Variable im Adapter habe, wie eine 'List ', wobei die Ints die Ids der ausgewählten Optionsfelder sind. Aber zuerst sehe meine aktualisierte Antwort. –