私人訂制Android本地圖片選擇器

效果圖

效果圖

需求分析

  • 網(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:

導(dǎo)入GalleryFinal源碼

詳情參考:
【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ù)量的圖片后磅废,無法重新回到圖片選擇頁面


    選擇圖片數(shù)量達(dá)到上限時無法進(jìn)入圖片選擇頁面
  • 無圖片選擇時,無法點(diǎn)擊浮動按鈕進(jìn)行返回


    無圖片時無法返回
  • 無圖片選擇時荆烈,預(yù)覽按鈕依然存在


    無圖片選擇時預(yù)覽按鈕依然存在并可以點(diǎn)擊

針對以上需要修改的功能拯勉,源碼修改如下:

  • 選擇圖片到達(dá)上限依然可以返回圖片選擇頁面
    因圖片選擇頁面的跳轉(zhuǎn)在openGalleryMuti方法里實(shí)現(xiàn):
// 多圖片選擇打開相冊
GalleryFinal.openGalleryMuti(Constants.REQUEST_CODE_GALLERY, mFunctionConfig, 
       mOnHandlerResultCallback);

所以我們來看看openGalleryMuti方法的源碼:


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)方法中:
    浮動按鈕點(diǎn)擊事件

    這段代碼僅僅在選中圖片的數(shù)量大于0的時候才執(zhí)行操作,所以我們添加一個條件波丰,修改后的代碼如下:
if (mSelectPhotoList.size() > 0) {
    if (!GalleryFinal.getFunctionConfig().isEditPhoto()) {
        resultData(mSelectPhotoList);
    } else {
        toPhotoEdit();
    }
} else {
    // 添加的代碼壳坪,使未選中圖片時也可返回
    resultData(mSelectPhotoList);
}
mSelectPhotoList初始化

考慮到選中圖片的列表在聲明時已經(jīng)初始化,所以不用擔(dān)心圖片返回的回調(diào)事件傳入空指針對象掰烟。

  • 未選擇圖片時不顯示預(yù)覽按鈕
    通過布局的id——iv_preview在PhotoSelectActivity中查找爽蝴,在refreshSelectCount方法里找到了對預(yù)覽按鈕可見性的設(shè)置:
    refreshSelectCount方法源碼

    從源碼中可以看到沐批,預(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辣苏,謝謝肝箱!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市稀蟋,隨后出現(xiàn)的幾起案子煌张,更是在濱河造成了極大的恐慌,老刑警劉巖退客,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骏融,死亡現(xiàn)場離奇詭異,居然都是意外死亡萌狂,警方通過查閱死者的電腦和手機(jī)档玻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茫藏,“玉大人误趴,你說我怎么就攤上這事∥癜粒” “怎么了冤留?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵碧囊,是天一觀的道長。 經(jīng)常有香客問我纤怒,道長,這世上最難降的妖魔是什么天通? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任泊窘,我火速辦了婚禮,結(jié)果婚禮上像寒,老公的妹妹穿的比我還像新娘烘豹。我一直安慰自己,他們只是感情好诺祸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布携悯。 她就那樣靜靜地躺著,像睡著了一般筷笨。 火紅的嫁衣襯著肌膚如雪憔鬼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天胃夏,我揣著相機(jī)與錄音轴或,去河邊找鬼。 笑死仰禀,一個胖子當(dāng)著我的面吹牛照雁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播答恶,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼饺蚊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悬嗓?” 一聲冷哼從身側(cè)響起污呼,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烫扼,沒想到半個月后曙求,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡映企,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年悟狱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堰氓。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡挤渐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出双絮,到底是詐尸還是另有隱情浴麻,我是刑警寧澤得问,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站软免,受9級特大地震影響宫纬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膏萧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一漓骚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧榛泛,春花似錦蝌蹂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沛简,卻和暖如春齐鲤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背覆享。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工佳遂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撒顿。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓丑罪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凤壁。 傳聞我的和親對象是個殘疾皇子吩屹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容