2015-06-28 32 views
0

當我嘗試創建一個帶有惰性加載的imageView作爲組視圖的可展開列表視圖時,我遇到了一個不好的問題。它發現每次打開一個組時,所有的組視圖都會重繪,但它們會被賦予一個隨機的convertView(而不是它們的),這會導致非常糟糕的閃爍,因爲之前的imageView會隨機傳送到錯誤的組。您可以通過以下示例來體驗此問題,該示例包含一個非常簡單的帶有延遲組繪製的ExpandableListView,可以非常好地突出顯示這種不需要的行爲。是否有更好的實現可以保留組開口上的項目/ convertView綁定?壞ExpandableListView組查看回收

public class MainActivity extends Activity { 

private static final int pad = 20; 
private ExpandableListView listView; 
private CustomAdapter adapter; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    List<GroupItem> items = new ArrayList<GroupItem>(); 
    for (int i = 1; i < 100; i++) { 
     GroupItem item = new GroupItem(); 
     item.title = "Group " + i; 
     for (int j = 0; j < i; j++) 
      item.items.add("Child " + j); 
     items.add(item); 
    } 

    adapter = new CustomAdapter(); 
    adapter.setData(items); 

    listView = new ExpandableListView(this); 
    listView.setAdapter(adapter); 

    listView.setOnGroupClickListener(new OnGroupClickListener() { 
     @Override 
     public boolean onGroupClick(ExpandableListView parent, View v, 
       int groupPosition, long id) { 
      if (listView.isGroupExpanded(groupPosition)) { 
       listView.collapseGroup(groupPosition); 
      } else { 
       listView.expandGroup(groupPosition); 
      } 
      return true; 
     } 
    }); 

    setContentView(listView); 
} 

private static class GroupItem { 
    String title; 
    List<String> items = new ArrayList<String>(); 
} 

/** 
* Adapter for our list of {@link GroupItem}s. 
*/ 
private class CustomAdapter extends BaseExpandableListAdapter { 

    private List<GroupItem> items; 

    public void setData(List<GroupItem> items) { 
     this.items = items; 
    } 

    @Override 
    public String getChild(int groupPosition, int childPosition) { 
     return items.get(groupPosition).items.get(childPosition); 
    } 

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

    @Override 
    public View getChildView(int groupPosition, int childPosition, 
      boolean isLastChild, View convertView, ViewGroup parent) { 
     String item = getChild(groupPosition, childPosition); 
     if (convertView == null) 
      convertView = new TextView(parent.getContext()); 
     TextView tv = (TextView) convertView; 
     tv.setPadding(pad, pad, pad, pad); 
     tv.setBackgroundColor(Color.LTGRAY); 
     tv.setText(item); 
     return convertView; 
    } 

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

    @Override 
    public GroupItem getGroup(int groupPosition) { 
     return items.get(groupPosition); 
    } 

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

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

    @Override 
    public View getGroupView(int groupPosition, boolean isExpanded, 
      View convertView, ViewGroup parent) { 
     final GroupItem item = getGroup(groupPosition); 
     if (convertView == null) 
      convertView = new TextView(parent.getContext()); 
     final TextView tv = (TextView) convertView; 
     tv.setPadding(pad, pad, pad, pad); 
     tv.setBackgroundColor(Color.WHITE); 
     new Handler().postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       tv.setText(item.title); 
      } 
     }, 1000); 
     return convertView; 
    } 

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

    @Override 
    public boolean isChildSelectable(int arg0, int arg1) { 
     return true; 
    } 
} 

} 

回答

0

你需要兩個視圖持有者一個父母和另一個子元素。

你可以嘗試這樣的事情。 公共類MyExpandableListAdapter擴展BaseExpandableListAdapter {

private Context mContext; 
private ArrayList<ContactNameItems> mListDataHeader; 
private ArrayList<String> selectedNumbers; 

private HashMap<String, List<ContactPhoneItems>> mListDataChild; 

private ChildViewHolder childViewHolder; 
private GroupViewHolder groupViewHolder; 

public MyExpandableListAdapter(Context context, 
     ArrayList<ContactNameItems> listDataHeader, 
     HashMap<String, List<ContactPhoneItems>> listDataChild, 
     ArrayList<String> listOfNumbers) { 

    mContext = context; 
    mListDataHeader = listDataHeader; 
    mListDataChild = listDataChild; 
    selectedNumbers = listOfNumbers; 

} 

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

@Override 
public ContactNameItems getGroup(int groupPosition) { 
    return mListDataHeader.get(groupPosition); 
} 

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

@Override 
public View getGroupView(int groupPosition, boolean isExpanded, 
     View convertView, ViewGroup parent) { 

    String contactName = getGroup(groupPosition).getName(); 
    Bitmap contactImage = getGroup(groupPosition).getImage(); 

    if (convertView == null) { 

     LayoutInflater inflater = (LayoutInflater) mContext 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = inflater.inflate(R.layout.contact_name_item, null); 

     groupViewHolder = new GroupViewHolder(); 

     groupViewHolder.mContactName = (TextView) convertView 
       .findViewById(R.id.lblListHeader); 

     groupViewHolder.mContactImage = (ImageView) convertView 
       .findViewById(R.id.ivContactPhoto); 

     convertView.setTag(groupViewHolder); 
    } else { 

     groupViewHolder = (GroupViewHolder) convertView.getTag(); 
    } 

    if (contactImage != null) { 
     groupViewHolder.mContactImage.setImageBitmap(contactImage); 

    } else { 
     groupViewHolder.mContactImage 
       .setImageResource(R.drawable.default_contact); 
    } 

    groupViewHolder.mContactName.setText(contactName); 

    return convertView; 
} 

@Override 
public int getChildrenCount(int groupPosition) { 
    return mListDataChild.get(mListDataHeader.get(groupPosition).getName()) 
      .size(); 
} 

@Override 
public ContactPhoneItems getChild(int groupPosition, int childPosition) { 
    return mListDataChild.get(mListDataHeader.get(groupPosition).getName()) 
      .get(childPosition); 
} 

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

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

    String numberText = getChild(groupPosition, childPosition).getNumber(); 
    String typeText = getChild(groupPosition, childPosition).getPhoneType(); 

    final int mGroupPosition = groupPosition; 

    if (convertView == null) { 

     LayoutInflater inflater = (LayoutInflater) this.mContext 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = inflater.inflate(R.layout.contact_detail_item, null); 

     childViewHolder = new ChildViewHolder(); 

     childViewHolder.mPhoneNumber = (TextView) convertView 
       .findViewById(R.id.tv_phone_number); 

     childViewHolder.mPhoneType = (TextView) convertView 
       .findViewById(R.id.tv_phone_type); 

     childViewHolder.mCheckBox = (CheckBox) convertView 
       .findViewById(R.id.checkBox); 

     childViewHolder.mCheckBox.setOnCheckedChangeListener(checkListener); 

     convertView.setTag(childViewHolder); 

    } else { 

     childViewHolder = (ChildViewHolder) convertView.getTag(); 
    } 

    childViewHolder.mPhoneNumber.setText(numberText); 
    childViewHolder.mPhoneType.setText(typeText); 

    ContactPhoneItems cpi = getChild(mGroupPosition, childPosition); 

    childViewHolder.mCheckBox.setTag(cpi); 
    childViewHolder.mCheckBox.setChecked(cpi.getSelected()); 

    // for managing the state of the boolean 
    // array according to the state of the 
    // CheckBox 

    childViewHolder.mCheckBox 
      .setOnClickListener(new View.OnClickListener() { 

       String contactNumber = mListDataChild 
         .get(mListDataHeader.get(mGroupPosition).getName()) 
         .get(childPosition).getNumber(); 

       public void onClick(View v) { 

        boolean isChecked = ((CheckBox) v).isChecked(); 

        if (isChecked) { 

         selectedNumbers.add(contactNumber); 

        } else { 

         selectedNumbers.remove(contactNumber); 
        } 

        getChild(mGroupPosition, childPosition).setSelected(isChecked); 
        notifyDataSetChanged(); 
       } 
      }); 

    return convertView; 
} 

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

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

public ArrayList<String> getSelectedNumbers() { 

    return selectedNumbers; 
} 

public final class GroupViewHolder { 

    TextView mContactName; 
    ImageView mContactImage; 
} 

public final class ChildViewHolder { 

    TextView mPhoneNumber; 
    TextView mPhoneType; 
    CheckBox mCheckBox; 
} 

OnCheckedChangeListener checkListener = new OnCheckedChangeListener() { 

    @Override 
    public void onCheckedChanged(CompoundButton buttonView, 
      boolean isChecked) { 

     ContactPhoneItems c = (ContactPhoneItems) buttonView.getTag(); 
     c.setSelected(isChecked); 
    } 
}; 

}

+0

我真的不認爲這個問題是由缺乏ViewHolders的,我不需要,因爲我的意見沒有反正膨脹引起的。你運行上面的例子嗎? –