Android-如何開發一個功能強大的圖片選擇器
圖片選擇器是Android開發中會經常用到的一個功能,特別對于社交類的應用,比如頭像設置,比如發圖片。自然ImagePicker的輪子很多,今天介紹一個功能強大的輪子SImagePicker
https://github.com/martin90s/ImagePicker
介紹
首先功能強大之處
- 首先基本的圖片讀取顯示,以及圖片更新監控
- 超大圖片預覽,比如一張19M,10000*5000px的圖片
- 圖片的裁剪功能
- 豐富的可配置項,支持拍照選取,選取張數定義,支持選擇的圖片過濾,
- 支持多種圖片加載器(Fresco,Glide等)
廢話不說,先看效果
***張頭像模式,第二張選擇多張圖片(包括動畫和順暢的跳轉),第三張是分片加載超大圖(19.5M,10000*5000px)
頭像模式,支持裁剪
多選圖片,流暢的頁面跳轉
超大圖預覽,可以看到漸變加載
如何使用
1.首先初始化(推薦在Application的oncreate中調用)
- SImagePicker.init(new PickerConfig.Builder().setAppContext(this)
- .setImageLoader(new FrescoImageLoader())
- .setToolbaseColor(getColor(R.color.colorPrimary))
- .build());
2.在需要選擇圖片的地方調用
- SImagePicker
- .from(MainActivity.this)
- .maxCount(9)
- .rowCount(3)
- .pickMode(SImagePicker.MODE_IMAGE)
- .fileInterceptor(new SingleFileLimitInterceptor())
- .forResult(REQUEST_CODE_IMAGE);
可配置項
1.全局配置(即初始化時傳入的PickerConfig,此配置作用于SImagePicker整個使用過程)
配置參數 | 參數含義 |
setImageLoader(ImageLoader) | 使用的圖片加載器。demo工程中實現了Fresco和Glide兩種ImageLoader,可以參考 |
setToolbarColor(int) | Picker的主色調,默認值是App的primaryColor |
setAppContext(Context) | Picker內部用到的Context,傳入ApplicationContext即可 |
2.單次配置(即每次調用SImagePicker時傳入的參數,此參數只對這次調用生效)
配置參數 | 參數含義 |
from(Activity or Fragment) | 調用圖片選擇器可從Activity或者Fragment進入,***的結果會在onActivityResult()返回,現在返回的結果有兩個值,用戶選擇的圖片的路徑列表data.getStringArrayListExtra(PhotoPickerActivity.EXTRA_RESULT_SELECTION);用戶是否選擇了原圖data.getBooleanExtra(PhotoPickerActivity.EXTRA_RESULT_ORIGINAL, false); |
maxCount(int) | 此次選擇允許的***選擇數量,默認是1.比如發朋友圈最多選擇9張圖就傳9 |
rowCount(int) |
圖片列表單排展示多少張圖 |
setSelected(List) | 默認已經被選中的圖片 |
pickMode(int) | 選圖的模式,現在有頭像模式和普通模式兩種,頭像模式選中圖片后默認會跳到圖片裁剪頁面且默認只能選擇一張 |
cropFilePath(String) | 頭像模式下裁剪圖片存放地址 |
showCamera(boolen) | 是否要展示拍照入口 |
pickText(int) | Picker里右下角展示的文字信息(比如配置選擇,發送,完成) |
fileInterceptor(FileChooseInterceptor) |
圖片過濾器,比如用戶選擇的單張圖片大小有限制,即可寫在這個攔截器中,當用戶選擇過大圖片時可以提示并且過濾 |
forResult(int requestCode) | 打開圖片選擇器,并且傳入requestCode |
獲取結果
在調用圖片選擇器的Fragment或者Activity中
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_IMAGE) {
- final ArrayList<String> pathList =
- data.getStringArrayListExtra(PhotoPickerActivity.EXTRA_RESULT_SELECTION);
- final boolean original =
- data.getBooleanExtra(PhotoPickerActivity.EXTRA_RESULT_ORIGINAL, false);
- }
- }
實現
圖片數據庫讀取CursorLoader
Android3.0中引入了加載器/裝載器(Loader)的功能,主要用于異步的方式加載數據庫。裝載器Loader的特點:
- 裝載器提供異步數據加載的能力
- 裝載器監視數據資源并且當內容改變時發送新的結果;
- 在配置改變后重建的時候,裝載器自動的重連***的裝載器游標,因此,不需要重新查詢數據。
此項目也是使用loader去加載和監控圖片數據,對于Photo和Album即圖片和相冊分別有一個loader和一個controller,loader主要用于加載對應的數據,controller主要用于數據讀取到后的刷新已經loader的釋放。
源碼中的對應
PhotoLoader初始化
- public static CursorLoader newInstance(Context context, Album album, long minSize) {
- if (album == null || album.isAll()) {
- return new PhotoLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION,
- SELECTION_SIZE, new String[] {minSize + ""}, ORDER_BY);
- }
- return new PhotoLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION,
- MediaStore.Images.Media.BUCKET_ID + " = ? and (" + SELECTION_SIZE + ")", new String[] {
- album.getId(), minSize + ""}, ORDER_BY);
- }
超大圖片加載
對于超大的圖片如何展示,這個是個比較棘手的問題
比如這張圖
http://7xpb9x.com1.z0.glb.clouddn.com/2017/01/20/b578e4755a32ac56a9c4b9a1f7e2822d.jpg
10000*5000的像素,接近20M。
這種圖片肯定無法一次全部load到內存中,可以稍微計算一下即使是RGB_565的方式全部load進內存也要占用幾乎90M的內存,顯然是不太可能。可以回頭看一下第三張demo gif,顯然用戶打開一張圖時,在默認情況下,并不要求能看到細節,當用戶點擊某區域放大時此時才會需要這一塊的清晰圖。那么如何展示這種超大圖的思路基本基本就是
- 首先拿到文件路徑,讀取出圖片的寬高,并且根據屏幕和圖片寬高計算出一個展示全圖的情況下的Samplesize,根據這個值去加載出一個全景的圖
- 對圖片進行分塊,分塊會分出不同放大倍數下(即選擇不同SampleSize)下的一個塊列表,比如放大2倍時,放大4倍時對應怎么分塊
- 當用戶點擊放大某一區域時,根據放大的倍數以及當前的中心點選擇對應的塊進行load和渲染
在SImagePicker項目中主要是用了subsamplingImageView
并且根據picker的需求做了些修改,來實現超大圖的預覽
圖片列表展示
展示
由于使用了cursorLoader,對于ListView的話有CursorAdapter可以使用,但是對于RecyclerView確沒有對應的Adapter,所以在源碼中可以看到實現了一個RecycleCursorAdapter,用于實現從cursor獲取數據已經自動刷新。
兼容
為了能夠兼容多個圖片加載器,SImagePicker抽象了一個ImageLoader接口用于讓使用者自定義對應的圖片加載器。
使用建議
SImagePicker提供了jitpack上的依賴庫,可以很快的接入業務中,但是由于大部分的APP對于ImagePicker的使用都有各種業務需求,且SImagePicker只是抽象出了比較通用的一些配置,用于讓使用者能快速集成,所以此處還是建議使用者盡可能源碼引用的方式的使用SImagePicker,既方便做一些調試,也可以很快的了解實現原理,說起來這種UI組件代碼應該是很好讀的,因為本身并不復雜。