私人訂制Android本地圖片選擇器
效果圖
需求分析
- 網格布局顯示本地圖片
- 支持圖片多選
- 支持選中的圖片預覽
- 未選擇圖片時不可預覽
- 由已選多圖變為無圖時可退出圖片選擇頁面
- 圖片已選達到上限后依然可以跳轉圖片選擇頁面
第三方框架使用
史上最強的安卓圖片選擇器—— GalleryFinal ;
實現目標
應用并修改第三方框架GalleryFinal源碼,實現效果圖的樣式。
具體實現
-
導入GalleryFinal源碼
從GalleryFinal的Github倉庫中拷貝倉庫地址,使用git指令cloneGalleryFinal源代碼到本地:
git clone https://github.com/pengjianbo/GalleryFinal.git
選擇Android Studio菜單欄File->New->import Module...,導入GalleryFinal源代碼到Android Studio:
導入GalleryFinal源碼
-
寫一個GridView
這里聲明一下,選擇圖片的Activity是GalleryFinal自帶的,所以我們這里要寫的GridView是用來顯示選中并返回的圖片,這里的代碼就不放出來了,效果圖如下:
未選擇時
選擇圖片時
本人實現的可支持最大圖片數量是5,在圖片選滿的時候依然顯示“+”,用以跳轉圖片選擇頁面選擇其他圖片。
-
初始化GalleryFinal配置
為防止代碼分開查看導致邏輯的混亂,將上述配置代碼一齊貼上,下面的代碼可放在跳轉圖片選擇界面的按鈕點擊事件中。 這里強調一下 :mThemeConfig = new ThemeConfig.Builder() .setTitleBarBgColor等方法傳參是整型,但是其傳入的是顏色值而非資源文件的id。
代碼注釋較詳細,其他不做過多講解:
// ------- 聲明 ------- // 主題配置 private ThemeConfig mThemeConfig; // 圖片加載器 private cn.finalteam.galleryfinal.ImageLoader mGlidImgLoader; // 滾動監聽事件 private PauseOnScrollListener mPauseOnScrollListener; // 功能配置 private FunctionConfig mFunctionConfig; // 核心配置 private CoreConfig mCoreConfig; // ------- 實現 ------- // 獲取標題欄背景顏色 int colorTitleBarBg = ContextCompat.getColor(Activity.this, R.color.titleBarBgColor); // 標題欄文字顏色 int colorTitleBarText = ContextCompat.getColor(Activity.this, R.color.titleBarTextColor); // 浮動按鈕常規顏色 int colorFabNormal = ContextCompat.getColor(Activity.this, R.color.color_ffaa2a); // 浮動按鈕點擊顏色 int colorFabPressed = ContextCompat.getColor(Activity.this, R.color.color_e29428); // 標題欄按鈕顏色 int colorTitleBarIcon = ContextCompat.getColor(MainActivity.this, R.color.colorTitleBarIcon); // 設置主題 mThemeConfig = new ThemeConfig.Builder() .setTitleBarBgColor(colorTitleBarBg) // 設置標題欄背景顏色 .setTitleBarTextColor(colorTitleBarText) // 設置標題欄文字顏色 .setFabNormalColor(colorFabNormal) // 設置浮動按鈕常規顏色 .setFabPressedColor(colorFabPressed) // 設置浮動按鈕點擊顏色 .setCheckSelectedColor(colorFabNormal) // 設置選中標記(對勾)的顏色和按鈕的顏色相同 .setTitleBarIconColor(colorTitleBarIcon) // 設置標題欄按鈕顏色 .setIconBack(R.drawable.ic_back) // 設置返回按鈕 .build(); // 初始化圖片加載器 mGlidImgLoader = new GlideImageLoader(); // 初始化監聽事件 mPauseOnScrollListener = new GlidePauseOnScrollListener(false, true); // 初始化功能配置 FunctionConfig.Builder funConBuilder = new FunctionConfig.Builder(); // 設置最多可選擇5張照圖片 funConBuilder.setMutiSelectMaxSize(5); // 設置圖片不可編輯 funConBuilder.setEnableEdit(false); // 設置圖片不可旋轉 funConBuilder.setEnableRotate(false); // 設置圖片不可裁剪 funConBuilder.setEnableCrop(false); // 設置不可通過照相選擇照片 funConBuilder.setEnableCamera(false); // 設置添加過濾集合,過濾掉之前選中的圖片 // funConBuilder.setFilter(mPhotoList); // 不過濾圖片,而是將之前選中的圖片設置為選中狀態 funConBuilder.setSelected(mPhotoList); // 設置可預覽 funConBuilder.setEnablePreview(true); // 功能配置 mFunctionConfig = funConBuilder.build(); // 初始化核心配置 mCoreConfig = new CoreConfig.Builder(ReportActivity.this, mGlidImgLoader, mThemeConfig) .setFunctionConfig(mFunctionConfig) // 添加功能配置 .setPauseOnScrollListener(mPauseOnScrollListener) // 滑動停止加載事件 .setNoAnimcation(true) // 無特效動畫 .build(); // 實例化 GalleryFinalGalleryFinal.init(mCoreConfig); // 多圖片選擇打開相冊 GalleryFinal.openGalleryMuti(Constants.REQUEST_CODE_GALLERY, mFunctionConfig, mOnHandlerResultCallback); // 初始化圖片加載器 initImageLoader(ReportActivity.this);
/**
- 初始化圖片加載器 *
- @param context
/
private void initImageLoader(Context context) {
// 圖片加載器配置
ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(this);
// 設置線程優先級
config.threadPriority(Thread.NORM_PRIORITY - 2);
// 禁止內存緩存
config.denyCacheImageMultipleSizesInMemory();
// 設置磁盤緩存文件名生成器
config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
// 設置磁盤緩存大小
config.diskCacheSize(20 1024 * 1024);
// 設置任務進程執行順序:先進后出
config.tasksProcessingOrder(QueueProcessingType.LIFO);
// 調試使用,若是發布版,需要移除代碼
config.writeDebugLogs();
// 初始化圖片加載器
ImageLoader.getInstance().init(config.build());
}</code></pre>
- 通過代碼設置圖片選擇器的標題欄背景顏色,標題文本顏色,浮動按鈕顏色;
- 通過監聽事件,達到滾動時不加載圖片,停下來時加載圖片,實現優化;
- 初始化功能配置;
-
選擇圖片返回的回調實現
/**
- 回調處理
*/
private GalleryFinal.OnHanlderResultCallback mOnHandlerResultCallback = new GalleryFinal.OnHanlderResultCallback() {
@Override
public void onHanlderSuccess(int reqeustCode, List<PhotoInfo> resultList) {
} @Override public void onHanlderFailure(int requestCode, String errorMsg) {// 清除原來列表中的圖片 mPhotoList.clear(); // 返回圖片列表 mPhotoList.addAll(resultList); // 刷新頁面 mPhotoAdapter.notifyDataSetChanged();
} };</code></pre> </li> </ul>// 錯誤提示 Toast.makeText(Activity.this, errorMsg, Toast.LENGTH_SHORT).show();
基于上述代碼,可得到效果圖如下:
初步效果圖
修改源碼
通過運行調試,發現框架中有些功能與需求不一致,因此我產生了修改源碼的想法,總結需要更改的原功能點如下:
選擇完達到上限數量的圖片后,無法重新回到圖片選擇頁面
選擇圖片數量達到上限時無法進入圖片選擇頁面
-
無圖片選擇時,無法點擊浮動按鈕進行返回
無圖片時無法返回
- 無圖片選擇時,預覽按鈕依然存在
無圖片選擇時預覽按鈕依然存在并可以點擊
針對以上需要修改的功能,源碼修改如下:
選擇圖片到達上限依然可以返回圖片選擇頁面
因圖片選擇頁面的跳轉在openGalleryMuti方法里實現:
// 多圖片選擇打開相冊 GalleryFinal.openGalleryMuti(Constants.REQUEST_CODE_GALLERY, mFunctionConfig, mOnHandlerResultCallback);
所以我們來看看openGalleryMuti方法的源碼:
openGalleryMuti方法源碼
可以發現,源碼中有這么一個判斷邏輯:
if (config.getSelectedList() != null && config.getSelectedList().size() > config.getMaxSize()) { if(callback != null){ callback.onHanlderFailure(requestCode, mCoreConfig.getContext().getString(R.string.select_max_tips)); } return; }
其作用是當選中的圖片數量超過最大值時,返回打開本地圖片選擇器失敗的提示信息。之前我們提到,需求中我們實際多顯示了一張圖片:
“添加”圖片
且在配置的時候傳入的是添加了一張圖片以后的圖片列表:
// 不過濾圖片,而是將之前選中的圖片設置為選中狀態 funConBuilder.setSelected(mPhotoList);
所以會導致界面無法跳轉,我們有三個策略:
1.將多添加的圖片放到adapter里面處理,adapter外部保持選中圖片數量與選擇頁面傳入圖片的數量一致
2.setSelected傳入圖片列表之前將mPhotoList移除多出的圖片
3.注釋掉源碼中對圖片數量上限的判斷
無圖選擇時,點擊浮動按鈕可以返回
可能有人不解,為何不點擊標題欄的返回按鈕返回而要點擊浮動按鈕返回?其原因是,若之前我選擇好圖片,但是想想,現在我不想要選擇的圖片了,這時候我們想把圖片清空掉,這時候需要點擊浮動按鈕,來更新選中圖片的列表。
想到這是浮動按鈕的點擊事件,所以我們到源碼的GallerySelectActivity中浮動按鈕的事件回調方法中:
浮動按鈕點擊事件
這段代碼僅僅在選中圖片的數量大于0的時候才執行操作,所以我們添加一個條件,修改后的代碼如下:
if (mSelectPhotoList.size() > 0) { if (!GalleryFinal.getFunctionConfig().isEditPhoto()) { resultData(mSelectPhotoList); } else { toPhotoEdit(); } } else { // 添加的代碼,使未選中圖片時也可返回 resultData(mSelectPhotoList); }
mSelectPhotoList初始化
考慮到選中圖片的列表在聲明時已經初始化,所以不用擔心圖片返回的回調事件傳入空指針對象。
-
未選擇圖片時不顯示預覽按鈕
通過布局的id—— iv_preview 在PhotoSelectActivity中查找,在refreshSelectCount方法里找到了對預覽按鈕可見性的設置:
refreshSelectCount方法源碼
從源碼中可以看到,預覽按鈕的可見性判斷邏輯僅僅與isEnablePreview有關,而沒有和選中的圖片數量進行關聯,所以我們修改代碼如下:
public void refreshSelectCount() { mTvChooseCount.setText(getString(R.string.selected, mSelectPhotoList.size(), GalleryFinal.getFunctionConfig().getMaxSize())); if (mSelectPhotoList.size() > 0 && GalleryFinal.getFunctionConfig().isMutiSelect()) { mIvClear.setVisibility(View.VISIBLE); if (GalleryFinal.getFunctionConfig().isEnablePreview()) { mIvPreView.setVisibility(View.VISIBLE); } } else { mIvClear.setVisibility(View.GONE); mIvPreView.setVisibility(View.GONE); } }
當選中圖片列表大小為0的時候,隱藏預覽按鈕;大于0的時候再根據isEnablePreview()來判斷是否顯示預覽按鈕。
修改布局和代碼邏輯
布局和代碼邏輯的修改,其思路與上一節 修改源碼 一樣,因需求的效果圖功能與GalleryFinal的功能基本一致,邏輯上并不需要做很多的修改,而布局的修改僅涉及到ImageButton變成Button,ImageView變成TextView以及控件位置的調整,在關聯控件上和點擊事件根據id來判斷事件處理上做相應修改即可,在此不做贅述。
總結
使用GalleryFinal訂制屬于自己的圖片選擇器并不難,只需要循著需求的功能點,按照代碼的邏輯一點點追蹤源碼并進行修改訂制即可。誠懇地說,GalleryFinal框架的可移植性確實很強,在此推薦大家了解一下!
來自:http://www.jianshu.com/p/fd5ebfc4725e
-