效果圖
需求分析
- 網(wǎng)格布局顯示本地圖片
- 支持圖片多選
- 支持選中的圖片預(yù)覽
- 未選擇圖片時不可預(yù)覽
- 由已選多圖變?yōu)闊o圖時可退出圖片選擇頁面
- 圖片已選達(dá)到上限后依然可以跳轉(zhuǎn)圖片選擇頁面
第三方框架使用
史上最強(qiáng)的安卓圖片選擇器——GalleryFinal;
簡書博客地址——http://www.reibang.com/p/48ddd6756b7a
實(shí)現(xiàn)目標(biāo)
應(yīng)用并修改第三方框架GalleryFinal源碼筐摘,實(shí)現(xiàn)效果圖的樣式衅斩。
具體實(shí)現(xiàn)
-
導(dǎo)入GalleryFinal源碼
從GalleryFinal的Github倉庫中拷貝倉庫地址,使用git指令cloneGalleryFinal源代碼到本地:
git clone https://github.com/pengjianbo/GalleryFinal.git
選擇Android Studio菜單欄File->New->import Module...障簿,導(dǎo)入GalleryFinal源代碼到Android Studio:
詳情參考:
【Mac流派】程序猿修煉之道(6)-技能篇之git指令
Android Studio導(dǎo)入第三方庫的三種方法
-
寫一個GridView
這里聲明一下馒铃,選擇圖片的Activity是GalleryFinal自帶的蟹腾,所以我們這里要寫的GridView是用來顯示選中并返回的圖片,這里的代碼就不放出來了,效果圖如下:
本人實(shí)現(xiàn)的可支持最大圖片數(shù)量是5,在圖片選滿的時候依然顯示“+”炼吴,用以跳轉(zhuǎn)圖片選擇頁面選擇其他圖片。 -
初始化GalleryFinal配置
- 通過代碼設(shè)置圖片選擇器的標(biāo)題欄背景顏色昼汗,標(biāo)題文本顏色,浮動按鈕顏色;
- 通過監(jiān)聽事件,達(dá)到滾動時不加載圖片叶洞,停下來時加載圖片,實(shí)現(xiàn)優(yōu)化禀崖;
- 初始化功能配置;
為防止代碼分開查看導(dǎo)致邏輯的混亂螟炫,將上述配置代碼一齊貼上波附,下面的代碼可放在跳轉(zhuǎn)圖片選擇界面的按鈕點(diǎn)擊事件中。這里強(qiáng)調(diào)一下:mThemeConfig = new ThemeConfig.Builder() .setTitleBarBgColor等方法傳參是整型,但是其傳入的是顏色值而非資源文件的id掸屡。
代碼注釋較詳細(xì)封寞,其他不做過多講解:
// ------- 聲明 -------
// 主題配置
private ThemeConfig mThemeConfig;
// 圖片加載器
private cn.finalteam.galleryfinal.ImageLoader mGlidImgLoader;
// 滾動監(jiān)聽事件
private PauseOnScrollListener mPauseOnScrollListener;
// 功能配置
private FunctionConfig mFunctionConfig;
// 核心配置
private CoreConfig mCoreConfig;
// ------- 實(shí)現(xiàn) -------
// 獲取標(biāo)題欄背景顏色
int colorTitleBarBg = ContextCompat.getColor(Activity.this, R.color.titleBarBgColor);
// 標(biāo)題欄文字顏色
int colorTitleBarText = ContextCompat.getColor(Activity.this, R.color.titleBarTextColor);
// 浮動按鈕常規(guī)顏色
int colorFabNormal = ContextCompat.getColor(Activity.this, R.color.color_ffaa2a);
// 浮動按鈕點(diǎn)擊顏色
int colorFabPressed = ContextCompat.getColor(Activity.this, R.color.color_e29428);
// 標(biāo)題欄按鈕顏色
int colorTitleBarIcon = ContextCompat.getColor(MainActivity.this, R.color.colorTitleBarIcon);
// 設(shè)置主題
mThemeConfig = new ThemeConfig.Builder()
.setTitleBarBgColor(colorTitleBarBg) // 設(shè)置標(biāo)題欄背景顏色
.setTitleBarTextColor(colorTitleBarText) // 設(shè)置標(biāo)題欄文字顏色
.setFabNormalColor(colorFabNormal) // 設(shè)置浮動按鈕常規(guī)顏色
.setFabPressedColor(colorFabPressed) // 設(shè)置浮動按鈕點(diǎn)擊顏色
.setCheckSelectedColor(colorFabNormal) // 設(shè)置選中標(biāo)記(對勾)的顏色和按鈕的顏色相同
.setTitleBarIconColor(colorTitleBarIcon) // 設(shè)置標(biāo)題欄按鈕顏色
.setIconBack(R.drawable.ic_back) // 設(shè)置返回按鈕
.build();
// 初始化圖片加載器
mGlidImgLoader = new GlideImageLoader();
// 初始化監(jiān)聽事件
mPauseOnScrollListener = new GlidePauseOnScrollListener(false, true);
// 初始化功能配置
FunctionConfig.Builder funConBuilder = new FunctionConfig.Builder();
// 設(shè)置最多可選擇5張照圖片
funConBuilder.setMutiSelectMaxSize(5);
// 設(shè)置圖片不可編輯
funConBuilder.setEnableEdit(false);
// 設(shè)置圖片不可旋轉(zhuǎn)
funConBuilder.setEnableRotate(false);
// 設(shè)置圖片不可裁剪
funConBuilder.setEnableCrop(false);
// 設(shè)置不可通過照相選擇照片
funConBuilder.setEnableCamera(false);
// 設(shè)置添加過濾集合,過濾掉之前選中的圖片
// funConBuilder.setFilter(mPhotoList);
// 不過濾圖片仅财,而是將之前選中的圖片設(shè)置為選中狀態(tài)
funConBuilder.setSelected(mPhotoList);
// 設(shè)置可預(yù)覽
funConBuilder.setEnablePreview(true);
// 功能配置
mFunctionConfig = funConBuilder.build();
// 初始化核心配置
mCoreConfig = new CoreConfig.Builder(ReportActivity.this, mGlidImgLoader, mThemeConfig)
.setFunctionConfig(mFunctionConfig) // 添加功能配置
.setPauseOnScrollListener(mPauseOnScrollListener) // 滑動停止加載事件
.setNoAnimcation(true) // 無特效動畫
.build();
// 實(shí)例化
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);
// 設(shè)置線程優(yōu)先級
config.threadPriority(Thread.NORM_PRIORITY - 2);
// 禁止內(nèi)存緩存
config.denyCacheImageMultipleSizesInMemory();
// 設(shè)置磁盤緩存文件名生成器
config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
// 設(shè)置磁盤緩存大小
config.diskCacheSize(20 * 1024 * 1024);
// 設(shè)置任務(wù)進(jìn)程執(zhí)行順序:先進(jìn)后出
config.tasksProcessingOrder(QueueProcessingType.LIFO);
// 調(diào)試使用狈究,若是發(fā)布版,需要移除代碼
config.writeDebugLogs();
// 初始化圖片加載器
ImageLoader.getInstance().init(config.build());
}
- 選擇圖片返回的回調(diào)實(shí)現(xiàn)
/**
* 回調(diào)處理
*/
private GalleryFinal.OnHanlderResultCallback mOnHandlerResultCallback = new GalleryFinal.OnHanlderResultCallback() {
@Override
public void onHanlderSuccess(int reqeustCode, List<PhotoInfo> resultList) {
// 清除原來列表中的圖片
mPhotoList.clear();
// 返回圖片列表
mPhotoList.addAll(resultList);
// 刷新頁面
mPhotoAdapter.notifyDataSetChanged();
}
@Override
public void onHanlderFailure(int requestCode, String errorMsg) {
// 錯誤提示
Toast.makeText(Activity.this, errorMsg, Toast.LENGTH_SHORT).show();
}
};
基于上述代碼盏求,可得到效果圖如下:
修改源碼
通過運(yùn)行調(diào)試抖锥,發(fā)現(xiàn)框架中有些功能與需求不一致,因此我產(chǎn)生了修改源碼的想法碎罚,總結(jié)需要更改的原功能點(diǎn)如下:
-
選擇完達(dá)到上限數(shù)量的圖片后磅废,無法重新回到圖片選擇頁面
-
無圖片選擇時,無法點(diǎn)擊浮動按鈕進(jìn)行返回
-
無圖片選擇時荆烈,預(yù)覽按鈕依然存在
針對以上需要修改的功能拯勉,源碼修改如下:
-
選擇圖片到達(dá)上限依然可以返回圖片選擇頁面
因圖片選擇頁面的跳轉(zhuǎn)在openGalleryMuti方法里實(shí)現(xiàn):
// 多圖片選擇打開相冊
GalleryFinal.openGalleryMuti(Constants.REQUEST_CODE_GALLERY, mFunctionConfig,
mOnHandlerResultCallback);
所以我們來看看openGalleryMuti方法的源碼:
可以發(fā)現(xiàn),源碼中有這么一個判斷邏輯:
if (config.getSelectedList() != null && config.getSelectedList().size() > config.getMaxSize()) {
if(callback != null){
callback.onHanlderFailure(requestCode, mCoreConfig.getContext().getString(R.string.select_max_tips));
}
return;
}
其作用是當(dāng)選中的圖片數(shù)量超過最大值時憔购,返回打開本地圖片選擇器失敗的提示信息宫峦。之前我們提到,需求中我們實(shí)際多顯示了一張圖片:
且在配置的時候傳入的是添加了一張圖片以后的圖片列表:
// 不過濾圖片玫鸟,而是將之前選中的圖片設(shè)置為選中狀態(tài)
funConBuilder.setSelected(mPhotoList);
所以會導(dǎo)致界面無法跳轉(zhuǎn)导绷,我們有三個策略:
1.將多添加的圖片放到adapter里面處理,adapter外部保持選中圖片數(shù)量與選擇頁面?zhèn)魅雸D片的數(shù)量一致
2.setSelected傳入圖片列表之前將mPhotoList移除多出的圖片
3.注釋掉源碼中對圖片數(shù)量上限的判斷
-
無圖選擇時鞋邑,點(diǎn)擊浮動按鈕可以返回
可能有人不解诵次,為何不點(diǎn)擊標(biāo)題欄的返回按鈕返回而要點(diǎn)擊浮動按鈕返回?其原因是枚碗,若之前我選擇好圖片逾一,但是想想,現(xiàn)在我不想要選擇的圖片了肮雨,這時候我們想把圖片清空掉遵堵,這時候需要點(diǎn)擊浮動按鈕,來更新選中圖片的列表怨规。
想到這是浮動按鈕的點(diǎn)擊事件陌宿,所以我們到源碼的GallerySelectActivity中浮動按鈕的事件回調(diào)方法中:
這段代碼僅僅在選中圖片的數(shù)量大于0的時候才執(zhí)行操作,所以我們添加一個條件波丰,修改后的代碼如下:
if (mSelectPhotoList.size() > 0) {
if (!GalleryFinal.getFunctionConfig().isEditPhoto()) {
resultData(mSelectPhotoList);
} else {
toPhotoEdit();
}
} else {
// 添加的代碼壳坪,使未選中圖片時也可返回
resultData(mSelectPhotoList);
}
考慮到選中圖片的列表在聲明時已經(jīng)初始化,所以不用擔(dān)心圖片返回的回調(diào)事件傳入空指針對象掰烟。
-
未選擇圖片時不顯示預(yù)覽按鈕
通過布局的id——iv_preview在PhotoSelectActivity中查找爽蝴,在refreshSelectCount方法里找到了對預(yù)覽按鈕可見性的設(shè)置:
從源碼中可以看到沐批,預(yù)覽按鈕的可見性判斷邏輯僅僅與isEnablePreview有關(guān),而沒有和選中的圖片數(shù)量進(jìn)行關(guān)聯(lián)蝎亚,所以我們修改代碼如下:
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);
}
}
當(dāng)選中圖片列表大小為0的時候九孩,隱藏預(yù)覽按鈕;大于0的時候再根據(jù)isEnablePreview()來判斷是否顯示預(yù)覽按鈕发框。
修改布局和代碼邏輯
布局和代碼邏輯的修改躺彬,其思路與上一節(jié)修改源碼一樣,因需求的效果圖功能與GalleryFinal的功能基本一致梅惯,邏輯上并不需要做很多的修改宪拥,而布局的修改僅涉及到ImageButton變成Button,ImageView變成TextView以及控件位置的調(diào)整个唧,在關(guān)聯(lián)控件上和點(diǎn)擊事件根據(jù)id來判斷事件處理上做相應(yīng)修改即可江解,在此不做贅述。
總結(jié)
使用GalleryFinal訂制屬于自己的圖片選擇器并不難徙歼,只需要循著需求的功能點(diǎn)犁河,按照代碼的邏輯一點(diǎn)點(diǎn)追蹤源碼并進(jìn)行修改訂制即可。誠懇地說魄梯,GalleryFinal框架的可移植性確實(shí)很強(qiáng)桨螺,在此推薦大家了解一下!
本篇文章的Demo已上傳Github酿秸,歡迎訪問指導(dǎo)灭翔!
原創(chuàng)不易,轉(zhuǎn)載請注明鏈接:http://www.reibang.com/p/fd5ebfc4725e辣苏,謝謝肝箱!