【问题标题】:Values of counter changes after scrolling ExpendableListView滚动 ExpandableListView 后计数器的值发生变化
【发布时间】:2018-10-10 01:40:48
【问题描述】:

我有一个 ExpandableListView 项目,在列表项上我有 TextView 和两个按钮,用于在点击时增加或减少 TextView 中的值。每次我尝试滚动列表时都会出现问题。如果我增加一项然后滚动列表,则值会混合(因为 ListView 不断回收其视图)并且我不知道如何修复它。

我已经尝试了很多我在这里找到的解决方案,所以是的,这可能是重复的,但我无法用我找到的任何方法解决我的问题。

我的 ExpandableListAdapter.java

    import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;


public class ExpandableListAdapter extends BaseExpandableListAdapter {

public static class ViewHolder {
    TextView childText;
    TextView counterText;
    Button addItemButton;
    Button deleteItemButton;

    int quantity = 0;

}


private Context context;
private List<String> listDataHeader;
private HashMap<String, List<String>> listHashMap;

public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listHashMap) {
    this.context = context;
    this.listDataHeader = listDataHeader;
    this.listHashMap = listHashMap;
}

@Override
public int getGroupCount() {
    return listDataHeader.size();
}

@Override
public int getChildrenCount(int groupPosition) {
    return listHashMap.get(listDataHeader.get(groupPosition)).size();
}

@Override
public Object getGroup(int groupPosition) {
    return listDataHeader.get(groupPosition);
}

@Override
public Object getChild(int groupPosition, int childPosition) {
    return listHashMap.get(listDataHeader.get(groupPosition)).get(childPosition);
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

@Override
public boolean hasStableIds() {
    return false;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    String headerTitle = (String) getGroup(groupPosition);

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_group, null);

    }
    TextView listHeader = (TextView) convertView.findViewById(R.id.list_header);
    listHeader.setTypeface(null, Typeface.BOLD);
    listHeader.setText(headerTitle);

    return convertView;
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

    final ViewHolder viewHolder;

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_item, null);

        TextView textListChild = (TextView) convertView.findViewById(R.id.list_item_header);
        TextView itemsCounter = (TextView) convertView.findViewById(R.id.items_counter);
        Button addItemButton = (Button) convertView.findViewById(R.id.plus_btn);

        viewHolder = new ViewHolder();
        viewHolder.childText = textListChild;
        viewHolder.counterText = itemsCounter;
        viewHolder.addItemButton = addItemButton;

        convertView.setTag(viewHolder);


    } else {
        viewHolder = (ViewHolder) convertView.getTag();

    }

    final String childText = (String) getChild(groupPosition, childPosition);
    viewHolder.childText.setText(childText);

    viewHolder.addItemButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            //int itemCount = Integer.parseInt((String)viewHolder.counterText.getText());
            //itemCount++;

            viewHolder.quantity++;
            viewHolder.counterText.setText( Integer.toString(viewHolder.quantity));

            PutOrderDrinks.addOrder(childText);

        }
    });


    return convertView;
}

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
       return true;
    } 
}

【问题讨论】:

    标签: java android listview adapter expandablelistview


    【解决方案1】:

    在 ViewHolder 中存储数量不是一个好主意。 希望下面的示例有所帮助:)

    MainActivity.java:

    public class MainActivity extends Activity {
    
    Button clearChecks, putOrder;
    ExpandableListView expandableListView;
    ExpandableListViewAdapter expandableListAdapter;
    int lastExpandedPosition = -1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        expandableListView = findViewById(R.id.expandedListView);
        clearChecks = findViewById(R.id.btnClearChecks);
        putOrder = findViewById(R.id.btnPutOrder);
    
        List<String> listTitle = genGroupList();
        expandableListAdapter = new ExpandableListViewAdapter(this, listTitle, genChildList(listTitle));
        expandableListView.setAdapter(expandableListAdapter);
    
        expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                if(lastExpandedPosition != -1 && (lastExpandedPosition != groupPosition)){
                    expandableListView.collapseGroup(lastExpandedPosition);
                }
                lastExpandedPosition = groupPosition;
            }
        });
        clearChecks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                expandableListAdapter.clearChecks();
            }
        });
        putOrder.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ArrayList<ChildItemSample> putOrder = expandableListAdapter.getOrderList();
                String msg = "";
                for(int i=0; i<putOrder.size(); i++){
                    msg += putOrder.get(i).getName() + ": " + putOrder.get(i).getQty() + "\n";
                }
                Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
            }
        });
    }
    
    private ArrayList<String> genGroupList(){
        ArrayList<String> listGroup = new ArrayList<>();
        for(int i=1; i<10; i++){
            listGroup.add("Group: " + i);
        }
        return listGroup;
    }
    
    private Map<String, List<ChildItemSample>> genChildList(List<String> header){
        Map<String, List<ChildItemSample>> listChild = new HashMap<>();
        for(int i=0; i<header.size(); i++){
            List<ChildItemSample> testDataList = new ArrayList<>();
            int a = (int)(Math.random()*8);
            for(int j=0; j<a; j++){
                ChildItemSample testItem = new ChildItemSample("Child " + (j + 1), 0);
                testDataList.add(testItem);
            }
            listChild.put(header.get(i), testDataList);
        }
        return listChild;
    }
    }
    

    ChildItemSample.java:

    public class ChildItemSample {
    private boolean checked = false;
    private String name;
    private int qty;
    
    public int getQty() {
        return qty;
    }
    
    public void setQty(int qty) {
        this.qty = qty;
    }
    
    public boolean isChecked() {
        return checked;
    }
    
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
    
    public String getName() {
        return name;
    }
    
    public ChildItemSample(String name, int qty){
        this.name = name;
        this.qty = qty;
    }
    }
    

    ExpandableListViewAdapter.java:

    public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
    private Context context;
    private List<String> listGroup;
    private Map<String, List<ChildItemSample>> listChild;
    private int checkedBoxesCount;
    private boolean[] checkedGroup;
    
    public ExpandableListViewAdapter(Context context, List<String> listGroup, Map<String,
            List<ChildItemSample>> listChild) {
        this.context = context;
        this.listGroup = listGroup;
        this.listChild = listChild;
        checkedBoxesCount = 0;
        checkedGroup = new boolean[listGroup.size()];
    }
    
    @Override
    public int getGroupCount() {
        return listGroup.size();
    }
    
    @Override
    public int getChildrenCount(int groupPosition) {
        return listChild.get(listGroup.get(groupPosition)).size();
    }
    
    @Override
    public String getGroup(int groupPosition) {
        return listGroup.get(groupPosition);
    }
    
    @Override
    public ChildItemSample getChild(int groupPosition, int childPosition) {
        return listChild.get(listGroup.get(groupPosition)).get(childPosition);
    }
    
    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }
    
    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }
    
    @Override
    public boolean hasStableIds() {
        return false;
    }
    
    @Override
    public View getGroupView(int groupPosition, boolean b, View view, ViewGroup viewGroup) {
        String itemGroup = getGroup(groupPosition);
        GroupViewHolder groupViewHolder;
        if(view == null){
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.expanded_list_group, null);
            groupViewHolder = new GroupViewHolder();
            groupViewHolder.tvGroup = view.findViewById(R.id.tv_group);
            groupViewHolder.cbGroup = view.findViewById(R.id.cb_group);
            groupViewHolder.cbGroup.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int pos = (int)view.getTag();
                    checkedGroup[pos] = !checkedGroup[pos];
                    for(ChildItemSample item : listChild.get(listGroup.get(pos))){
                        item.setChecked(checkedGroup[pos]);
                    }
                    notifyDataSetChanged();
                }
            });
            view.setTag(groupViewHolder);
        }else {
            groupViewHolder = (GroupViewHolder)view.getTag();
        }
        groupViewHolder.tvGroup.setText(String.format("%s (%d)", itemGroup, getChildrenCount(groupPosition)));
        if(checkedGroup[groupPosition]) groupViewHolder.cbGroup.setChecked(true);
        else groupViewHolder.cbGroup.setChecked(false);
        groupViewHolder.cbGroup.setTag(groupPosition);
        return view;
    }
    
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
        ChildItemSample expandedListText = getChild(groupPosition,childPosition);
        ChildViewHolder childViewHolder;
        if(view == null){
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.expanded_list_item, null);
            childViewHolder = new ChildViewHolder();
            childViewHolder.tvChild = view.findViewById(R.id.tv_child);
            childViewHolder.cbChild = view.findViewById(R.id.cb_child);
            childViewHolder.tvQty = view.findViewById(R.id.tv_qty);
            childViewHolder.btInc = view.findViewById(R.id.bt_inc);
            childViewHolder.btDec = view.findViewById(R.id.bt_dec);
            childViewHolder.cbChild.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    CheckBox cb = (CheckBox) view;
                    Pos pos = (Pos) cb.getTag();
                    ChildItemSample selectedItem = getChild(pos.group, pos.child);
                    selectedItem.setChecked(cb.isChecked());
                    if(cb.isChecked()){
                        checkedBoxesCount++;
                        Toast.makeText(context,"Checked value is: " + getChild(pos.group, pos.child).getName(),
                                Toast.LENGTH_SHORT).show();
                    }else {
                        checkedBoxesCount--;
                        if(checkedBoxesCount == 0){
                            Toast.makeText(context,"nothing checked",Toast.LENGTH_SHORT).show();
                        }else {
                            Toast.makeText(context,"unchecked",Toast.LENGTH_SHORT).show();
                        }
                    }
                    notifyDataSetChanged();
                }
            });
            childViewHolder.btInc.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Button bt = (Button) view;
                    Pos pos = (Pos) bt.getTag();
                    ChildItemSample selectedItem = getChild(pos.group, pos.child);
                    selectedItem.setQty(selectedItem.getQty() + 1);
                    notifyDataSetChanged();
                }
            });
            childViewHolder.btDec.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Button bt = (Button) view;
                    Pos pos = (Pos) bt.getTag();
                    ChildItemSample selectedItem = getChild(pos.group, pos.child);
                    if(selectedItem.getQty() > 0) selectedItem.setQty(selectedItem.getQty() - 1);
                    notifyDataSetChanged();
                }
            });
        }else {
            childViewHolder = (ChildViewHolder)view.getTag();
        }
        childViewHolder.cbChild.setChecked(expandedListText.isChecked());
        childViewHolder.tvChild.setText(expandedListText.getName() + " :");
        childViewHolder.tvQty.setText("" + expandedListText.getQty());
    
        childViewHolder.cbChild.setTag(new Pos(groupPosition, childPosition));
        childViewHolder.btInc.setTag(new Pos(groupPosition, childPosition));
        childViewHolder.btDec.setTag(new Pos(groupPosition, childPosition));
        view.setTag(childViewHolder);
        return view;
    }
    
    public void clearChecks() {
        for(int i=0; i<checkedGroup.length; i++) checkedGroup[i] = false;
        for(List<ChildItemSample> value : listChild.values()) {
            for (ChildItemSample sample : value) {
                sample.setChecked(false);
            }
        }
        checkedBoxesCount = 0;
        notifyDataSetChanged();
    }
    
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
    
    private class GroupViewHolder {
        CheckBox cbGroup;
        TextView tvGroup;
    }
    
    private class ChildViewHolder {
        CheckBox cbChild;
        TextView tvChild;
        TextView tvQty;
        Button btInc;
        Button btDec;
    }
    
    private class Pos {
        int group;
        int child;
    
        Pos(int group, int child){
            this.group = group;
            this.child = child;
        }
    }
    
    public ArrayList<ChildItemSample> getOrderList(){
        ArrayList<ChildItemSample> overallOrder = new ArrayList<>();
        for(int i=0; i<getGroupCount(); i++){
            for(int j=0; j<getChildrenCount(i); j++){
                if(getChild(i,j).getQty() > 0){
                    ChildItemSample newOrder = new ChildItemSample(getGroup(i) + ">" +
                            getChild(i, j).getName(), getChild(i, j).getQty());
                    overallOrder.add(newOrder);
                }
            }
        }
        return overallOrder;
    }
    }
    

    activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
                <Button
                    android:id="@+id/btnClearChecks"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="Clear Checks" />
                <Button
                    android:id="@+id/btnPutOrder"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="Put Order" />
        </LinearLayout>
        <ExpandableListView
            android:id="@+id/expandedListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </ExpandableListView>
    </LinearLayout>
    

    expanded_list_group.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants" >
    <CheckBox
        android:id="@+id/cb_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="40dp"
        android:layout_gravity="center_vertical" />
    <TextView
        android:id="@+id/tv_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text"
        android:textSize="30sp" />
    </LinearLayout>
    

    expanded_list_item.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <CheckBox
        android:id="@+id/cb_child"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="60dp" />
    <TextView
        android:id="@+id/tv_child"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/cb_child"
        android:text="Child: "
        android:textSize="20sp" />
    <TextView
        android:id="@+id/tv_qty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/tv_child"
        android:text="0"
        android:textSize="20sp" />
    <Button
        android:id="@+id/bt_inc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/bt_dec"
        android:text="+" />
    <Button
        android:id="@+id/bt_dec"
        android:layout_marginRight="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:text="-" />
    </RelativeLayout>
    

    【讨论】:

      【解决方案2】:

      试试这个适配器:

      public class ExpandableListAdapter extends BaseExpandableListAdapter {
      
      class ViewHolder {
          TextView childText;
          TextView counterText;
          Button addItemButton;
          Button deleteItemButton;
      }
      
      class ChildItem{
          String name;
          int quantity;
          ChildItem(String name, int quantity){
              this.name = name;
              this.quantity = quantity;
          }
      }
      
      class Pos{
          int group;
          int child;
          Pos(int group, int child){
              this.group = group;
              this.child = child;
          }
      }
      
      private Context context;
      private List<String> listDataHeader;
      //private HashMap<String, List<String>> listHashMap;
      private HashMap<String, List<ChildItem>> listChildMap;
      
      public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listHashMap) {
          this.context = context;
          this.listDataHeader = listDataHeader;
          listChildMap = new HashMap<>();
          for(int i=0; i<getGroupCount(); i++){
              List<ChildItem> listTemp = new ArrayList<>();
              for(int j=0; j<listHashMap.get(listDataHeader.get(i)).size(); j++){
                  listTemp.add(new ChildItem(listHashMap.get(listDataHeader.get(i)).get(j), 0));
              }
              listChildMap.put(listDataHeader.get(i), listTemp);
          }
      }
      
      @Override
      public int getGroupCount() {
          return listDataHeader.size();
      }
      
      @Override
      public int getChildrenCount(int groupPosition) {
          return listChildMap.get(listDataHeader.get(groupPosition)).size();
      }
      
      @Override
      public String getGroup(int groupPosition) {
          return listDataHeader.get(groupPosition);
      }
      
      @Override
      public ChildItem getChild(int groupPosition, int childPosition) {
          return listChildMap.get(listDataHeader.get(groupPosition)).get(childPosition);
      }
      
      @Override
      public long getGroupId(int groupPosition) {
          return groupPosition;
      }
      
      @Override
      public long getChildId(int groupPosition, int childPosition) {
          return childPosition;
      }
      
      @Override
      public boolean hasStableIds() {
          return false;
      }
      
      @Override
      public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
          String headerTitle = getGroup(groupPosition);
          if(convertView == null) {
              LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              convertView = inflater.inflate(R.layout.list_group, null);
          }
          TextView listHeader = (TextView) convertView.findViewById(R.id.list_header);
          listHeader.setTypeface(null, Typeface.BOLD);
          listHeader.setText(headerTitle);
          return convertView;
      }
      
      @Override
      public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
          ViewHolder viewHolder;
          if(convertView == null) {
              LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              convertView = inflater.inflate(R.layout.list_item, null);
              TextView textListChild = (TextView) convertView.findViewById(R.id.list_item_header);
              TextView itemsCounter = (TextView) convertView.findViewById(R.id.items_counter);
              Button addItemButton = (Button) convertView.findViewById(R.id.plus_btn);
              viewHolder = new ViewHolder();
              viewHolder.childText = textListChild;
              viewHolder.counterText = itemsCounter;
              viewHolder.addItemButton = addItemButton;
          } else {
              viewHolder = (ViewHolder) convertView.getTag();
          }
          ChildItem child = getChild(groupPosition, childPosition);
          viewHolder.childText.setText(child.name);
          viewHolder.counterText.setText("" + child.quantity);
          viewHolder.addItemButton.setOnClickListener(new View.OnClickListener(){
              @Override
              public void onClick(View v) {
                  Pos pos = (Pos)v.getTag();
                  ChildItem selectedItem = getChild(pos.group, pos.child);
                  selectedItem.quantity = selectedItem.quantity + 1;
                  notifyDataSetChanged();
      
                  PutOrderDrinks.addOrder(selectedItem.name);
              }
          });
          viewHolder.addItemButton.setTag(new Pos(groupPosition, childPosition));
          convertView.setTag(viewHolder);
          return convertView;
      }
      
      @Override
      public boolean isChildSelectable(int groupPosition, int childPosition) {
          return true;
      }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多