在上一篇博客《Universal-ImageLoader源码解析》中,我们从源码的角度分析了ImageLoader,这篇博客我们就开始结合RecyclerView和ImageLoader打造一个图片系统。
在我的项目中有一个多图选择的需求,但是系统的图库只能选择一张图片,所以我们只能自己来做一个简单的图片。利用RecyclerView和ImageLoader可以很轻松的实现这个功能,下面我们先来看看效果吧。
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怎么写的
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) {
}
}
}
整体代码非常简单,实现了一个可多选图片的图库功能。