在上一篇博客[《Universal-ImageLoader源码解析》](http://blog.csdn.net/qibin0506/article/details/48222355)中,我们从源码的角度分析了ImageLoader,这篇博客我们就开始结合RecyclerView和ImageLoader打造一个图片系统。
### 需求
在我的项目中有一个多图选择的需求,但是系统的图库只能选择一张图片,所以我们只能自己来做一个简单的图片。利用RecyclerView和ImageLoader可以很轻松的实现这个功能,下面我们先来看看效果吧。
![](https://box.kancloud.cn/2016-02-18_56c55b3be00d0.jpg "")
### 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) {
}
}
}
~~~
整体代码非常简单,实现了一个可多选图片的图库功能。
- 前言
- 高逼格UI-ASD(Android Support Design)
- AndroidSupportDesign之TabLayout使用详解
- RecyclerView的高级用法——定制动画
- Android官方数据绑定框架DataBinding(一)
- Android官方数据绑定框架DataBinding(二)
- 你所不知道的Activity转场动画——ActivityOptions
- RecyclerView+ImageLoader打造多选图库
- Android Material Design动画
- RecyclerView添加Header的正确方式
- CoordinatorLayout高级用法-自定义Behavior