ExpandableListView子项ImageView资源切换及按钮点击处理问题求助
Hey there, let's dig into this issue you're facing with the ImageSwitcher in your ExpandableListView's child item. Looking at your code, I can spot a few key problems that are causing abnormal behavior when switching image resources. Let's break them down and fix them step by step.
Key Issues in Your Current Code
- Incorrect ConvertView Reuse: Right now, you're inflating a new layout every time
getChildViewis called—even whenconvertViewis not null. This completely bypasses the View reuse mechanism of ExpandableListView, leading to memory bloat and lost state when scrolling. - Duplicate Click Listener Binding: For
groupPosition == 3, you're setting click listeners onbtmandbtm1every timegetChildViewruns (whenconvertViewexists). This means multiple listeners get attached to the same buttons, causing unexpected behavior like multiple image switches per click or state inconsistencies. - No State Persistence: You're not saving the current state of the ImageSwitcher (which image is active). When the view gets reused, it resets to the default state instead of retaining the user's selection.
Fixed Implementation with ViewHolder Pattern
Let's refactor the code using the ViewHolder pattern to handle view reuse properly, bind listeners once, and persist selection state.
First, create ViewHolder classes for each child layout type:
// Base ViewHolder to unify all types private abstract class BaseViewHolder {} // ViewHolder for groupPosition 3 (sort_by_date_child_layout) private class DateSortViewHolder extends BaseViewHolder { ImageSwitcher bookedonImage; Button btm, btm1; // Track current selection state: 0 = default, 1 = ascending, 2 = descending int currentSortState = 0; DateSortViewHolder(View itemView) { bookedonImage = itemView.findViewById(R.id.booedOnImage); btm = itemView.findViewById(R.id.btm); btm1 = itemView.findViewById(R.id.btm1); // Initialize ImageSwitcher factory ONCE bookedonImage.setFactory(() -> { ImageView myView = new ImageView(mContext); myView.setScaleType(ImageView.ScaleType.FIT_CENTER); return myView; }); // Bind click listeners ONCE here btm.setOnClickListener(v -> { currentSortState = 1; bookedonImage.setImageResource(R.drawable.ascending_active); }); btm1.setOnClickListener(v -> { currentSortState = 2; bookedonImage.setImageResource(R.drawable.decending_active); }); } // Restore the saved state when the view is reused void restoreState() { switch (currentSortState) { case 1: bookedonImage.setImageResource(R.drawable.ascending_active); break; case 2: bookedonImage.setImageResource(R.drawable.decending_active); break; default: // Set your default drawable here if needed bookedonImage.setImageResource(/* your default drawable ID */); break; } } } // Add ViewHolders for other group positions if you need to handle their views private class BookingStatusViewHolder extends BaseViewHolder { BookingStatusViewHolder(View itemView) { // Initialize views for booking_status_child_layout here } } private class FilterByViewHolder extends BaseViewHolder { FilterByViewHolder(View itemView) { // Initialize views for filterby_child_layout here } } private class TransferStatusViewHolder extends BaseViewHolder { TransferStatusViewHolder(View itemView) { // Initialize views for transfer_status_child_layout here } }
Then update the getChildView method to use these ViewHolders:
@Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { BaseViewHolder viewHolder; LayoutInflater infalInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (convertView == null) { // Inflate the correct layout based on groupPosition switch (groupPosition) { case 0: convertView = infalInflater.inflate(R.layout.booking_status_child_layout, parent, false); viewHolder = new BookingStatusViewHolder(convertView); break; case 1: convertView = infalInflater.inflate(R.layout.filterby_child_layout, parent, false); viewHolder = new FilterByViewHolder(convertView); break; case 2: convertView = infalInflater.inflate(R.layout.transfer_status_child_layout, parent, false); viewHolder = new TransferStatusViewHolder(convertView); break; case 3: convertView = infalInflater.inflate(R.layout.sort_by_date_child_layout, parent, false); viewHolder = new DateSortViewHolder(convertView); break; default: convertView = infalInflater.inflate(R.layout.booking_status_child_layout, parent, false); viewHolder = new BookingStatusViewHolder(convertView); break; } convertView.setTag(viewHolder); } else { // Reuse the existing ViewHolder viewHolder = (BaseViewHolder) convertView.getTag(); } // Restore saved state for the date sort view if (groupPosition == 3) { ((DateSortViewHolder) viewHolder).restoreState(); } // Add any other view population logic for other group positions here return convertView; }
Additional Tips
- State Persistence Across Config Changes: If you need to retain the sort state across screen rotations or other configuration changes, save
currentSortStatein a ViewModel or persist it in your adapter's data model. - Clean Up Unused Code: Remove redundant variables like
childView,groupName, and unused view references to keep the code maintainable. - Correct Inflation: Using
parentas the second parameter ininflate()ensures the layout uses the correct LayoutParams from the parent ExpandableListView.
内容的提问来源于stack exchange,提问作者singh.indolia
相关产品推荐
相关产品推荐

