在上一篇博客[《Universal-ImageLoader源碼解析》](http://blog.csdn.net/qibin0506/article/details/48222355)中,我們從源碼的角度分析了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) {
}
}
}
~~~
整體代碼非常簡單,實現了一個可多選圖片的圖庫功能。
- 前言
- 高逼格UI-ASD(Android Support Design)
- AndroidSupportDesign之TabLayout使用詳解
- RecyclerView的高級用法——定制動畫
- Android官方數據綁定框架DataBinding(一)
- Android官方數據綁定框架DataBinding(二)
- 你所不知道的Activity轉場動畫——ActivityOptions
- RecyclerView+ImageLoader打造多選圖庫
- Android Material Design動畫
- RecyclerView添加Header的正確方式
- CoordinatorLayout高級用法-自定義Behavior