企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
在上一篇博客[《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) { } } } ~~~ 整体代码非常简单,实现了一个可多选图片的图库功能。