前言
最近项目中需要使用到图片选择器,网上搜索了一下,这方面的库有很多,最终是参考的ImageSelector的源代码实现。在使用的过程中,按照交互需求,我新增了一下功能,并修复了几个bug。最后我自己做了一些封装,采用Builder的设计模式设计实现了一个更加通用的库。在此做个记录,
代码地址:https://github.com/yushiwo/Universal-Image-Selector
模块设计
具体代码的逻辑实现,我就不在这边讲了,大家有兴趣可以看下源码~
在对模块结构设计过程中,我参考了Universal-Image-Loader的设计思想。对外暴露ImageSelector.java和ImageSelectorConfigration.java类,用户通过ImageSelectorConfigration.java配置组件相关功能和样式;然后通过ImageSelector.java获取configration初始化组件以及启动组件的相关界面。
ImageSelector
/** * @author hzzhengrui * @Date 16/10/20 * @Description */public class ImageSelector { private static final String TAG = ImageSelector.class.getSimpleName(); private static final String WARNING_RE_INIT_CONFIG = "Try to initialize ImageSelector which had already been initialized before. " + "To re-init ImageSelector with new configuration call ImageSelector.destroy() at first."; private static final String ERROR_INIT_CONFIG_WITH_NULL = "ImageSelector configuration can not be initialized with null"; private static final String ERROR_NOT_INIT = "ImageSelector must be init with configuration before using"; private static ImageSelector sInstance; private ImageSelectorConfiguration configuration; public static ImageSelector getInstance(){ if (sInstance == null) { synchronized (ImageSelector.class) { if (sInstance == null) { sInstance = new ImageSelector(); } } } return sInstance; } // TODO: 16/10/20 实现config设置 public void init(ImageSelectorConfiguration configuration){ if(configuration == null){ throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL); } if(this.configuration == null){ this.configuration = configuration; ImageSelectorProxy.getInstance().setConfiguration(configuration); }else { Log.w(TAG, WARNING_RE_INIT_CONFIG); } } public boolean isInited() { return configuration != null; } private void checkConfiguration() { if (configuration == null) { throw new IllegalStateException(ERROR_NOT_INIT); } } public void destroy() { if (configuration != null) { configuration = null; } } /** * 开启图片选择页面 * @param activity * @param imageList */ public void launchSelector(Activity activity, ArrayList<String> imageList){ checkConfiguration(); ImageSelectorActivity.start(activity, imageList); } /** * 开启图片可删除选中图片的预览界面 * @param activity * @param imageList * @param position */ public void launchDeletePreview(Activity activity, ArrayList<String> imageList, int position){ checkConfiguration(); ImagePreviewActivity.startDeletePreview(activity, imageList, position); } }
ImageSelectorConfiguration
/** * @author hzzhengrui * @Date 16/10/20 * @Description*/public class ImageSelectorConfiguration { /** 最多可以选择图片的数目 */ public int maxSelectNum = -1; /** 图片选择界面的列数 */ public int spanCount = -1; public int selectMode = -1; public boolean isShowCamera = true; public boolean isEnablePreview = true; public boolean isEnableCrop = false; public Drawable imageOnLoading = null; public int imageResOnLoading = 0; public Drawable imageOnError = null; public int imageResOnError = 0; int titleBarColor = -1; int statusBarColor = -1; float titleHeight = -1; public ImageSelectorConfiguration(final Builder builder) { maxSelectNum = builder.maxSelectNum; spanCount = builder.spanCount; selectMode = builder.selectMode; isShowCamera = builder.isShowCamera; isEnablePreview = builder.isEnablePreview; isEnableCrop = builder.isEnableCrop; imageOnLoading = builder.imageOnLoading; imageResOnLoading = builder.imageResOnLoading; imageOnError = builder.imageOnError; imageResOnError = builder.imageResOnError; titleBarColor = builder.titleBarColor; statusBarColor = builder.statusBarColor; titleHeight = builder.titleHeight; } /** * 生成默认的图片选择器配置 * @param context * @return */ public static ImageSelectorConfiguration createDefault(Context context){ return new Builder(context).build(); } public static class Builder{ public static final int DEFAULT_MAX_SELECT_NUM = 9; public static final int DEFAULT_SPAN_COUNT = 4; public static final int DEFAULT_SELECT_MODE = ImageSelectorConstant.MODE_MULTIPLE; private Context context; /** 最多可以选择图片的数目 */ private int maxSelectNum = DEFAULT_MAX_SELECT_NUM; /** 图片选择界面的列数 */ private int spanCount = DEFAULT_SPAN_COUNT; private int selectMode = DEFAULT_SELECT_MODE; private boolean isShowCamera = true; private boolean isEnablePreview = true; private boolean isEnableCrop = false; private Drawable imageOnLoading = null; private int imageResOnLoading = 0; private Drawable imageOnError = null; private int imageResOnError = 0; private int titleBarColor = -1; private int statusBarColor = -1; private float titleHeight = -1; public Builder(Context context) { this.context = context.getApplicationContext(); } /** * 设置做多可选图片的数目 * @param maxSelectNum * @return */ public Builder setMaxSelectNum(int maxSelectNum){ this.maxSelectNum = maxSelectNum; return this; } /** * 设置图片选择页面展示的列数 * @param spanCount * @return */ public Builder setSpanCount(int spanCount){ this.spanCount = spanCount; return this; } /** * 设置选择模式,单选或者多选 * @param selectMode * @return */ public Builder setSelectMode(int selectMode) { this.selectMode = selectMode; return this; } /** * 设置是否可裁剪 * @param enableCrop * @return */ public Builder setEnableCrop(boolean enableCrop) { isEnableCrop = enableCrop; return this; } /** * 设置是否支持选择时候预览 * @param enablePreview * @return */ public Builder setEnablePreview(boolean enablePreview) { isEnablePreview = enablePreview; return this; } /** * 设置是否显示拍照按钮 * @param showCamera * @return */ public Builder setShowCamera(boolean showCamera) { isShowCamera = showCamera; return this; } /** * 设置图片加载时候的默认图 * @param * @return */ public Builder setImageOnLoading(Drawable image) { this.imageOnLoading = image; return this; } public Builder setImageOnLoading(int imageRes){ this.imageResOnLoading = imageRes; return this; } public Builder setImageOnError(Drawable image) { this.imageOnError = image; return this; } public Builder setImageOnError(int imageRes){ this.imageResOnError = imageRes; return this; } /** * 设置选择器titlebar的颜色 * @param colorRes * @return */ public Builder setTitleBarColor(int colorRes){ this.titleBarColor = colorRes; return this; } /** * 设置选择器statusbar的颜色 * @param colorRes * @return */ public Builder setStatusBarColor(int colorRes){ this.statusBarColor = colorRes; return this; } public Builder setTitleHeight(float titleHeight){ this.titleHeight = titleHeight; return this; } public ImageSelectorConfiguration build(){ initEmptyFieldsWithDefaultValues(); return new ImageSelectorConfiguration(this); } private void initEmptyFieldsWithDefaultValues() { if(maxSelectNum <= 0){ maxSelectNum = DEFAULT_MAX_SELECT_NUM; } if(spanCount <= 0){ spanCount = DEFAULT_SPAN_COUNT; } if(selectMode <= 0){ selectMode = DEFAULT_SELECT_MODE; } if(imageResOnLoading == 0 && imageOnLoading == null){ imageResOnLoading = R.drawable.uis_ic_placeholder; } if(imageResOnError == 0 && imageOnError == null){ imageResOnError = R.drawable.uis_ic_placeholder; } if(titleBarColor == -1){ titleBarColor = R.color.uis_black; } if(statusBarColor == -1){ statusBarColor = R.color.uis_black; } if(titleHeight <= 0){ titleHeight = 48; } } } }
在组件内部,通过一个代理类ImageSelectorProxy.java,统一处理configration的相关配置
/** * @author hzzhengrui * @Date 16/10/24 * @Description*/public class ImageSelectorProxy implements IProxy{ private static final String ERROR_NOT_INIT = "ImageSelector must be init with configuration before using"; private static ImageSelectorProxy sInstance; ImageSelectorConfiguration configuration; public static ImageSelectorProxy getInstance(){ if (sInstance == null) { synchronized (ImageSelector.class) { if (sInstance == null) { sInstance = new ImageSelectorProxy(); } } } return sInstance; } /** * 设置图片选择器的配置 * @param configuration */ public void setConfiguration(ImageSelectorConfiguration configuration){ this.configuration = configuration; } private void checkConfiguration() { if (configuration == null) { throw new IllegalStateException(ERROR_NOT_INIT); } } @Override public int getMaxSelectNum() { checkConfiguration(); return configuration.maxSelectNum; } @Override public int getSpanCount() { checkConfiguration(); return configuration.spanCount; } @Override public int getSelectMode() { checkConfiguration(); return configuration.selectMode; } @Override public boolean isEnablePreview() { checkConfiguration(); return configuration.isEnablePreview; } @Override public boolean isShowCamera() { checkConfiguration(); return configuration.isShowCamera; } @Override public boolean isEnableCorp() { checkConfiguration(); return configuration.isEnableCrop; } @Override public Drawable getImageOnLoading(Resources res) { checkConfiguration(); return configuration.imageResOnLoading != 0 ? res.getDrawable(configuration.imageResOnLoading) : configuration.imageOnLoading; } @Override public Drawable getImageOnError(Resources res) { checkConfiguration(); return configuration.imageResOnError != 0 ? res.getDrawable(configuration.imageResOnError) : configuration.imageOnError; } @Override public int getTitleBarColor(Resources res) { checkConfiguration(); return res.getColor(configuration.titleBarColor); } @Override public int getStatusBarColor(Resources res) { checkConfiguration(); return res.getColor(configuration.statusBarColor); } @Override public float getTitleHeight() { checkConfiguration(); return configuration.titleHeight; } }
使用
build.gradle配置
compile 'com.netease.imageSelector:android-imageselector-lib:1.0.2'
AndroidManifest配置
// 设置权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET"/> // 注册activity <activity android:name="com.netease.imageSelector.view.ImageSelectorActivity" android:theme="@style/Theme.AppCompat.NoActionBar" /> <activity android:name="com.netease.imageSelector.view.ImagePreviewActivity" android:theme="@style/Theme.AppCompat.NoActionBar" /> <activity android:name="com.netease.imageSelector.view.ImageCropActivity" android:theme="@style/Theme.AppCompat.NoActionBar" />
初始化
在需要使用此组件的Activity的onCreate方法中,或者在自定义Application的onCreate方法中初始化。
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // 获取默认配置 ImageSelectorConfiguration configuration = ImageSelectorConfiguration.createDefault(this); // 自定义图片选择器// ImageSelectorConfiguration configuration = new ImageSelectorConfiguration.Builder(this)// .setMaxSelectNum(9)// .setSpanCount(4)// .setSelectMode(ImageSelectorConstant.MODE_MULTIPLE)// .setTitleHeight(48)// .build(); ImageSelector.getInstance().init(configuration); } }
启动组件
/** * 开启图片选择页面 * @param activity * @param imageList */public void launchSelector(Activity activity, ArrayList<String> imageList)
/** * 开启图片可删除选中图片的预览界面 * @param activity * @param imageList * @param position */public void launchDeletePreview(Activity activity, ArrayList<String> imageList, int position) ImagePreviewActivity.startDeletePreview(activity, imageList, position)
开启图片预览界面(带删除功能)
开启图片选择界面
处理回调结果
组件的界面,都是通过startActivityForResult的方式启动,所以,我们只需在自己调起组件的界面,处理返回结果即可。
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (data == null) { return; } // 接收图片选择器返回结果,更新所选图片集合 if (requestCode == REQUEST_PREVIEW || requestCode == REQUEST_IMAGE) { ArrayList<String> newFiles = data.getStringArrayListExtra(OUTPUT_LIST); if (newFiles != null) { updateUI(newFiles); } } }
因为时间的原因,还没有实现可配置图片缓存相关,之后有时间会加上~大家在使用库的过程中,有任何问题,欢迎反馈哈~
共同学习,写下你的评论
评论加载中...
作者其他优质文章