RecyclerView+ImageLoader打造多选图库

在上一篇博客《Universal-ImageLoader源码解析》中,我们从源码的角度分析了ImageLoader,这篇博客我们就开始结合RecyclerView和ImageLoader打造一个图片系统。

需求

在我的项目中有一个多图选择的需求,但是系统的图库只能选择一张图片,所以我们只能自己来做一个简单的图片。利用RecyclerView和ImageLoader可以很轻松的实现这个功能,下面我们先来看看效果吧。

Activity的实现

activity的实现很简单,我们先来看看代码,

public class GalleryActivity extends BaseActivity {

    private RecyclerView mRecyclerView;
    private GridLayoutManager mLayoutManager;
    private ArrayList<GalleryImage> mImages; // 所有图片
    private ImageGalleryAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gallery_layout);
        setupViews();

        // 获取图片
        new OpusBiz().getImages(new OnImagesListener() {
            @Override
            public void onResult(ArrayList<GalleryImage> images) {
                if(images == null || images.isEmpty()) return;
                mImages = images;
                setAdapter();
            }
        });
    }

    @Override
    protected void setupViews() {
        super.setupViews();
        setNormalTitle(R.string.select_image_text);
        mTitleBar.setRightText(R.string.ok);

        mRecyclerView = (RecyclerView) findViewById(R.id.rv_gallery);
        mLayoutManager = new GridLayoutManager(this, 4, GridLayoutManager.HORIZONTAL, false);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    }

    private void setAdapter() {
        mAdapter = new ImageGalleryAdapter(mRecyclerView, mImages);
        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    protected void onRightClick() {
        ArrayList<GalleryImage> images = mAdapter.getSelected();

        Intent intent = getIntent();
        intent.putExtra(Constants.EXTRA_GALLERY_IMAGE, images);
        setResult(RESULT_OK, intent);
        onLeftClick();
    }
}

首先我们看看setupViews,这里面find了RecyclerView,并且给他设置了一个GridLayoutManager,这样我们的RecyclerView显示出来就是一个网格的布局了,是不是很简单!new OpusBiz().getImages()是从通过系统数据库获取图片并回调,这里面的代码我们稍后再看,最后我们new了一个ImageGalleryAdapter,并且将这个Adapter设置给了RecyclerView。

接下来我们看看怎么获取的图片吧。

图片的获取

public class OpusBiz {
    /** * 从系统数据库中获取图库图片 * @param li */
    public void getImages(final OnImagesListener li) {
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if(msg.what == Constants.MSG_SUCCESS)
                    li.onResult((ArrayList<GalleryImage>) msg.obj);
            }
        };

        new Thread(new Runnable() {
            @Override
            public void run() {
                handler.obtainMessage(Constants.MSG_SUCCESS, getImages()).sendToTarget();
            }
        }).start();
    }

    /** * 从系统数据库中获取图库图片 * @return */
    private ArrayList<GalleryImage> getImages() {
        ArrayList<GalleryImage> images = new ArrayList<GalleryImage>();
        GalleryImage image;
        final String[] columns = { MediaStore.Images.Media.DATA,
                MediaStore.Images.Media._ID };
        final String orderBy = MediaStore.Images.Media.DATE_TAKEN;
        Cursor imagecursor = App.getInstance().getContentResolver()
                .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns,
                        null, null, orderBy + " DESC");
        for (int i = 0; i < imagecursor.getCount(); i++) {
            imagecursor.moveToPosition(i);
            int dataColumnIndex = imagecursor
                    .getColumnIndex(MediaStore.Images.Media.DATA);
            image = new GalleryImage();
            image.setUri(imagecursor.getString(dataColumnIndex));
            images.add(image);
        }
        return images;
    }

    /** * 获取图库图片 */
    public interface OnImagesListener {
        public void onResult(ArrayList<GalleryImage> images);
    }
}

这里面开启了一个线程去查询系统数据库,获取图片的路径,然后然后一个ArrayList中,最后回调。
接下来我们继续看看Adapter怎么写的

ImageGalleryAdapter

public class ImageGalleryAdapter extends RecyclerView.Adapter<ImageGalleryAdapter.ImageViewHolder> {

    private RecyclerView mRecyclerView;
    private ArrayList<GalleryImage> mImages;
    private ArrayList<GalleryImage> mSelected;

    public ImageGalleryAdapter(RecyclerView recyclerView, ArrayList<GalleryImage> images) {
        mRecyclerView = recyclerView;
        mImages = images;
        mSelected = new ArrayList<GalleryImage>(UploadOpusActivity.MAX_COUNT);
    }

    public ArrayList<GalleryImage> getSelected() {
        return mSelected;
    }

    @Override
    public int getItemCount() {
        return mImages.size();
    }

    @Override
    public void onBindViewHolder(final ImageViewHolder holder, int position) {
        final GalleryImage image = mImages.get(holder.getLayoutPosition());
        String uri = image.getUri();
        if(!uri.startsWith("file://")) uri = "file://" + image.getUri();
        ImageLoaderUtils.getInstance().displayImage(uri, holder.image);
        holder.item.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                boolean isChecked = !image.isChecked();
                // 如果是选择状态
                if(isChecked) {
                    // 则需要判断当前选择了几个
                    if(mSelected.size() >= UploadOpusActivity.MAX_COUNT) return;
                    // 添加到选择的列表中
                    mSelected.add(image);
                }else {
                    // 取消选择
                    mSelected.remove(image);
                }

                // 纯粹为了显示
                holder.cb.setChecked(isChecked);
                image.setChecked(isChecked);
            }
        });

        holder.cb.setChecked(image.isChecked());
    }

    @Override
    public ImageViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gallery_item, parent, false);
        return new ImageViewHolder(view);
    }

    class ImageViewHolder extends RecyclerView.ViewHolder {
        View item;
        ImageView image;
        CheckBox cb;
        public ImageViewHolder(View view) {
            super(view);
            item = view;
            image = (ImageView) view.findViewById(R.id.iv_gallery_item_image);
            cb = (CheckBox) view.findViewById(R.id.cb_gallery_item_check);

            int size = mRecyclerView.getMeasuredHeight() / 4;
            LayoutParams p = image.getLayoutParams();
            p.width = size;
            p.height = size;
        }
    }
}

也是一个简单的RecyclerView的adapter,主要看onBindViewHolder里的代码,

ImageLoaderUtils.getInstance().displayImage(uri, holder.image);
holder.item.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    boolean isChecked = !image.isChecked();
    // 如果是选择状态
    if(isChecked) {
      // 则需要判断当前选择了几个
      if(mSelected.size() >= UploadOpusActivity.MAX_COUNT) return;
      // 添加到选择的列表中
      mSelected.add(image);
    }else {
      // 取消选择
      mSelected.remove(image);
    }

    // 纯粹为了显示
    holder.cb.setChecked(isChecked);
    image.setChecked(isChecked);
  }
});

holder.cb.setChecked(image.isChecked());

首先通过ImageLoader加载了图片,然后监听了整个item的点击事件,如果是将要去选择,我们需要判断选择的最大数,如果大于我们允许的最大选择数则直接返回,否则,将选择的图片放到选择类别中,如果当前是选择状态,则就是要去取消选择,直接从选择列表中移除。最后,我们改变了CheckBox的选择状态。
最后的最后,附上对ImageLoader封装的代码,

public class ImageLoaderUtils {
    private static ImageLoaderUtils sInstance;

    private DisplayImageOptions mOptions;

    public synchronized static ImageLoaderUtils getInstance() {
        if(sInstance == null) sInstance = new ImageLoaderUtils();
        return sInstance;
    }

    private ImageLoaderUtils() {
        setDefault();
    }

    private void setDefault() {
        mOptions = new DisplayImageOptions.Builder()
        .showImageOnLoading(R.drawable.default_icon)
        .showImageForEmptyUri(R.drawable.default_icon)
        .showImageOnFail(R.drawable.default_icon)
        .cacheInMemory(true)
        .cacheOnDisk(true)
        .bitmapConfig(Config.RGB_565) // 2倍图
        .considerExifParams(true)
        .displayer(new SimpleBitmapDisplayer()).build();
    }

    /** * 设置默认的图标 * @param res * @return */
    public ImageLoaderUtils defaultIcon(int res) {
        mOptions = new DisplayImageOptions.Builder()
        .showImageOnLoading(res)
        .showImageForEmptyUri(res)
        .showImageOnFail(res)
        .cacheInMemory(true)
        .cacheOnDisk(true)
        .bitmapConfig(Config.RGB_565) // 2倍图
        .considerExifParams(true)
        .displayer(new SimpleBitmapDisplayer()).build();

        return sInstance;
    }

    /** * 获取图片 * @param url 图片url * @param l 回调 */
    public void loadImage(final String url, final ImageLoaderListener l) {
        ImageLoader.getInstance().loadImage(url, mOptions, l);
    }

    /** * 显示圆形图片 * @param uri * @param imageView * @param radius 半径 */
    public void displayRoundImage(String uri, ImageView imageView, int radius) {
        DisplayImageOptions options = new DisplayImageOptions.Builder()
        .showImageOnLoading(R.drawable.default_icon)
        .showImageForEmptyUri(R.drawable.default_icon)
        .showImageOnFail(R.drawable.default_icon)
        .cacheInMemory(true)
        .cacheOnDisk(true)
        .considerExifParams(true)
        .bitmapConfig(Config.RGB_565) // 2倍图
        .displayer(new RoundedBitmapDisplayer(radius)).build();

        displayImage(uri, imageView, options);
    }

    public void displayImage(String uri, ImageView imageView) {
        displayImage(uri, imageView, mOptions);
// ImageLoader.getInstance().displayImage(uri, imageView, mOptions);
        setDefault(); // 恢复默认
    }

    private void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
        if(uri == null) return;
        ImageLoader.getInstance().displayImage(uri, imageView, options);
    }

    public static abstract class ImageLoaderListener implements ImageLoadingListener {

        @Override
        public void onLoadingStarted(String imageUri, View view) {

        }

        @Override
        public void onLoadingFailed(String imageUri, View view,
                FailReason failReason) {

        }

        @Override
        public void onLoadingCancelled(String imageUri, View view) {

        }
    }
}

整体代码非常简单,实现了一个可多选图片的图库功能。

你可能感兴趣的:(图库)