为了账号安全,请及时绑定邮箱和手机立即绑定

一款好用的图片选择器

标签:
Android

前言

最近项目中需要使用到图片选择器,网上搜索了一下,这方面的库有很多,最终是参考的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);
        }
    }
}

因为时间的原因,还没有实现可配置图片缓存相关,之后有时间会加上~大家在使用库的过程中,有任何问题,欢迎反馈哈~

原文链接:http://www.apkbus.com/blog-605567-62477.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消