当滚动带有可检查项目的自定义GridView时,复选框会错误地启用随机项目

时间:2015-07-28 06:00:18

标签: android

我正在尝试制作一个充满复选框的GridView。我遵循ViewHolder模式来回收视图并尝试将复选框设置为正确的值,但由于某种原因,我似乎无法使它们不重复。 在我的调试工作之后,我发现我的SparseBooleanArray正在被正确更新 - 只是将它应用到视图似乎打开了错误的复选框,即使我将它们应用到正确的位置。 这是我的GridView的整个适配器 - 相关部分是getView和onCheckedChanged

// Our image adapter takes our list of thumbnails and creates a selectable grid full of asychroniously loaded images.
public class ThumbnailImageAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener {
    Context mContext;
    LayoutInflater mInflater;
    SparseBooleanArray mCheckedStates;
    private int mItemHeight = 0;
    private int mNumColumns = 0;
    private RelativeLayout.LayoutParams mImageViewLayoutParams;
    private ArrayList<String> mList;
    private ArrayList<String> mImageFullResUrls;
    private String nextURL;

    public ThumbnailImageAdapter(Context context) {
        super();
        mContext = context;
        mInflater = LayoutInflater.from(mContext);
        mImageViewLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        clear();
    }

    public ArrayList<String> getCheckedItems() {
        ArrayList<String> checkedItems = new ArrayList<String>();
        for (int i = 0; i < mList.size(); i++) {
            if (mCheckedStates.get(i)) {
                checkedItems.add(mImageFullResUrls.get(i));
            }
        }
        return checkedItems;
    }

    public boolean hasSelectedItems() {
        return mCheckedStates.indexOfValue(true) >= 0;
    }

    @Override
    public int getCount() {
        // If columns have yet to be determined, return no items
        if (getNumColumns() == 0) {
            return 0;
        }

        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mImageFullResUrls.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup container) {
        if(position >= getCount()) {
            return null;
        }
        final ThumbnailViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.selectable_imageview, null);
            holder = new ThumbnailViewHolder();
            holder.checkbox = (CheckBox) convertView.findViewById(R.id.photo_checkbox);
            holder.imageView = (SmartImageView) convertView.findViewById(R.id.photo_imageview);
            convertView.setTag(holder);
        } else {
            holder = (ThumbnailViewHolder) convertView.getTag();
        }

        holder.checkbox.setTag(position);
        holder.checkbox.setOnCheckedChangeListener(this);
        holder.checkbox.setChecked(mCheckedStates.get(position, false));


        holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        holder.imageView.setLayoutParams(mImageViewLayoutParams);
        // Finally load the image asynchronously into the ImageView, this also takes care of
        // setting a placeholder image while the background thread runs
        holder.imageView.setImageUrl(mList.get(position));

        final View finalView = convertView;
        convertView.post(new Runnable() {
            @Override
            public void run() {
                Rect delegateArea = new Rect();
                holder.imageView.getHitRect(delegateArea);
                finalView.setTouchDelegate(new TouchDelegate(delegateArea, holder.checkbox));
            }
        });

        return convertView;
    }

    public void setItemHeight(int height) {
        if (height == mItemHeight) {
            return;
        }
        mItemHeight = height;
        mImageViewLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, mItemHeight);
        notifyDataSetChanged();
    }

    public int getNumColumns() {
        return mNumColumns;
    }

    public void setNumColumns(int numColumns) {
        mNumColumns = numColumns;
    }

    public void appendImage(String thumbUrl, String fullResUrl) {
        if (!mList.contains(thumbUrl)) {
            mList.add(thumbUrl);
            mImageFullResUrls.add(fullResUrl);
            if (getActivity() != null) {
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mAdapter.notifyDataSetChanged();
                    }
                });
            }
        }
    }

    public void prependImage(String thumbUrl, String fullResUrl) {
        if (!mList.contains(thumbUrl)) {
            mList.add(0, thumbUrl);
            mImageFullResUrls.add(0, fullResUrl);
            SparseBooleanArray shiftedArray = new SparseBooleanArray(mList.size());
            // Shift our entire array one down (there has to be a better way to do this)
            for (int i = 0; i < mCheckedStates.size(); i++) {
                shiftedArray.put(mCheckedStates.keyAt(i) + 1, mCheckedStates.valueAt(i));
            }
            mCheckedStates = shiftedArray;
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mAdapter.notifyDataSetChanged();
                }
            });
        }
    }

    public void clear() {
        mList = new ArrayList<String>();
        mImageFullResUrls = new ArrayList<String>();
        mCheckedStates = new SparseBooleanArray();
    }

    public String getNextURL() {
        return this.nextURL;
    }

    public void setNextURL(String nextURL) {
        this.nextURL = nextURL;
    }

    public ArrayList<String> getThumbnailURLs() {
        return mList;
    }

    @Override
    public void onCheckedChanged(CompoundButton checkBoxView, boolean isChecked) {
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
        final int numPhotos = Integer.parseInt(settings.getString("num_photos", null));
        if (mAdapter.getCheckedItems().size() > numPhotos) {
            checkBoxView.setChecked(false); // Don't allow the user to select more than numPhotos photos
        }
        // This animates our image "pressed" and "unpressed" states
        mCheckedStates.put((Integer) checkBoxView.getTag(), isChecked);
        final ImageView image = (ImageView) ((ViewGroup) checkBoxView.getParent()).findViewById(R.id.photo_imageview);
        int dpi = getResources().getDisplayMetrics().densityDpi;
        int _12dp = (int) (12 * (dpi / 160f));
        ValueAnimator animator;

        if (isChecked) {
            animator = ValueAnimator.ofInt(image.getPaddingRight(), _12dp);
        } else {
            animator = ValueAnimator.ofInt(image.getPaddingRight(), 0);
        }

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int v = (Integer) valueAnimator.getAnimatedValue();
                image.setPadding(v, v, v, v);
            }
        });
        animator.setDuration(100);
        animator.start();

        mOnImageSelectionChangeListener.onImageSelectionChange(getCheckedItems());
        getActivity().invalidateOptionsMenu();
    }
}

static class ThumbnailViewHolder {
    CheckBox checkbox;
    SmartImageView imageView;
}

1 个答案:

答案 0 :(得分:0)

这是由于网格视图回收视图的方式。

为您的适配器实施以下内容

implements CompoundButton.OnCheckedChangeListener

然后有一个SpareBooleanArray来跟踪已检查的陈述

SparseBooleanArray mCheckStates; 

然后

mCheckStates = new SparseBooleanArray(your data size);

在getView中

holder.chkSelect.setTag(position);
holder.chkSelect.setChecked(mCheckStates.get(position, false));
holder.chkSelect.setOnCheckedChangeListener(this); 

然后覆盖

public boolean isChecked(int position) {
        return mCheckStates.get(position, false);
    }

public void setChecked(int position, boolean isChecked) {
    mCheckStates.put(position, isChecked);

}

public void toggle(int position) {
    setChecked(position, !isChecked(position));

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

 mCheckStates.put((Integer) buttonView.getTag(), isChecked);    

}

同时移动此

 holder.imageView = (SmartImageView) convertView.findViewById(R.id.photo_imageview);

到getView的if部分

并更改此

  imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  imageView.setLayoutParams(mImageViewLayoutParams);
    // Finally load the image asynchronously into the ImageView, this also takes care of
    // setting a placeholder image while the background thread runs
 imageView.setImageUrl(mList.get(position));

  holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  holder.imageView.setLayoutParams(mImageViewLayoutParams);
    // Finally load the image asynchronously into the ImageView, this also takes care of
    // setting a placeholder image while the background thread runs
  holder.imageView.setImageUrl(mList.get(position));

你可以找到一个类似的例子@

How to get checkbox state in a gridview