效果圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcukTYilzN4MGMiRGN2cjZ3MmZ5ATMyQWOxEzYmFzY5QmYvwVN5MjMxgTOtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
【注意】Demo已更新到最新版本,并稍作調整。(2019-07-05)
之前出過一篇 Android 選擇圖檔、上傳圖檔之ImagePicker,這個是okgo作者出的,就一般需求來講是夠了,但是沒有壓縮,需要自己去搞。
後來業務需求提升,頁面要美,體驗要好,便不是那麼滿足需求了,所幸在github上找到PictureSelector(然後當時沒多久Matisse就開源了…可以看這裡Android 選擇圖檔、上傳圖檔之Matisse),也不用自己再撸一個了,下面來介紹介紹PictureSelector
github
https://github.com/LuckSiege/PictureSelector
目前是一直在維護的,支援從相冊或拍照選擇圖檔或視訊、音頻,支援動态權限擷取、裁剪(單圖or多圖裁剪)、壓縮、主題自定義配置等功能、适配android 6.0+系統,而且你能遇到的問題,README文檔都有解決方案。
功能特點
功能齊全,且相容性好,作者也做了相容測試
1.适配android6.0+系統
2.解決部分機型裁剪閃退問題
3.解決圖檔過大oom閃退問題
4.動态擷取系統權限,避免閃退
5.支援相片or視訊的單選和多選
6.支援裁剪比例設定,如常用的 1:1、3:4、3:2、16:9 預設為圖檔大小
7.支援視訊預覽
8.支援gif圖檔
9.支援.webp格式圖檔
10.支援一些常用場景設定:如:是否裁剪、是否預覽圖檔、是否顯示相機等
11.新增自定義主題設定
12.新增圖檔勾選樣式設定
13.新增圖檔裁剪寬高設定
14.新增圖檔壓縮處理
15.新增錄視訊最大時間設定
16.新增視訊清晰度設定
17.新增QQ選擇風格,帶數字效果
18.新增自定義 文字顔色 背景色讓風格和項目更搭配
19.新增多圖裁剪功能
20.新增LuBan多圖壓縮
21.新增單獨拍照功能
22.新增壓縮大小設定
23.新增Luban壓縮檔次設定
24.新增圓形頭像裁剪
25.新增音頻功能查詢
主題配置
這個就想怎麼改就怎麼改了
<!--預設樣式 注意* 樣式隻可修改,不能删除任何一項 否則報錯-->
<style name="picture.default.style" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<!--标題欄背景色-->
<item name="colorPrimary">@color/bar_grey</item>
<!--狀态欄背景色-->
<item name="colorPrimaryDark">@color/bar_grey</item>
<!--是否改變圖檔清單界面狀态欄字型顔色為黑色-->
<item name="picture.statusFontColor">false</item>
<!--傳回鍵圖示-->
<item name="picture.leftBack.icon">@drawable/picture_back</item>
<!--标題下拉箭頭-->
<item name="picture.arrow_down.icon">@drawable/arrow_down</item>
<!--标題上拉箭頭-->
<item name="picture.arrow_up.icon">@drawable/arrow_up</item>
<!--标題文字顔色-->
<item name="picture.title.textColor">@color/white</item>
<!--标題欄右邊文字-->
<item name="picture.right.textColor">@color/white</item>
<!--圖檔清單勾選樣式-->
<item name="picture.checked.style">@drawable/checkbox_selector</item>
<!--開啟圖檔清單勾選數字模式-->
<item name="picture.style.checkNumMode">false</item>
<!--選擇圖檔樣式0/9-->
<item name="picture.style.numComplete">false</item>
<!--圖檔清單底部背景色-->
<item name="picture.bottom.bg">@color/color_fa</item>
<!--圖檔清單預覽文字顔色-->
<item name="picture.preview.textColor">@color/tab_color_true</item>
<!--圖檔清單已完成文字顔色-->
<item name="picture.complete.textColor">@color/tab_color_true</item>
<!--圖檔已選數量圓點背景色-->
<item name="picture.num.style">@drawable/num_oval</item>
<!--預覽界面标題文字顔色-->
<item name="picture.ac_preview.title.textColor">@color/white</item>
<!--預覽界面已完成文字顔色-->
<item name="picture.ac_preview.complete.textColor">@color/tab_color_true</item>
<!--預覽界面标題欄背景色-->
<item name="picture.ac_preview.title.bg">@color/bar_grey</item>
<!--預覽界面底部背景色-->
<item name="picture.ac_preview.bottom.bg">@color/bar_grey_90</item>
<!--預覽界面狀态欄顔色-->
<item name="picture.status.color">@color/bar_grey_90</item>
<!--預覽界面傳回箭頭-->
<item name="picture.preview.leftBack.icon">@drawable/picture_back</item>
<!--是否改變預覽界面狀态欄字型顔色為黑色-->
<item name="picture.preview.statusFontColor">false</item>
<!--裁剪頁面标題背景色-->
<item name="picture.crop.toolbar.bg">@color/bar_grey</item>
<!--裁剪頁面狀态欄顔色-->
<item name="picture.crop.status.color">@color/bar_grey</item>
<!--裁剪頁面标題文字顔色-->
<item name="picture.crop.title.color">@color/white</item>
<!--相冊檔案夾清單選中圖示-->
<item name="picture.folder_checked_dot">@drawable/orange_oval</item>
</style>
複制
功能配置
// 進入相冊 以下是例子:用不到的api可以不寫
PictureSelector.create(MainActivity.this)
.openGallery()//全部.PictureMimeType.ofAll()、圖檔.ofImage()、視訊.ofVideo()、音頻.ofAudio()
.theme()//主題樣式(不設定為預設樣式) 也可參考demo values/styles下 例如:R.style.picture.white.style
.maxSelectNum()// 最大圖檔選擇數量 int
.minSelectNum()// 最小選擇數量 int
.imageSpanCount(4)// 每行顯示個數 int
.selectionMode()// 多選 or 單選 PictureConfig.MULTIPLE or PictureConfig.SINGLE
.previewImage()// 是否可預覽圖檔 true or false
.previewVideo()// 是否可預覽視訊 true or false
.enablePreviewAudio() // 是否可播放音頻 true or false
.isCamera()// 是否顯示拍照按鈕 true or false
.imageFormat(PictureMimeType.PNG)// 拍照儲存圖檔格式字尾,預設jpeg
.isZoomAnim(true)// 圖檔清單點選 縮放效果 預設true
.sizeMultiplier(0.5f)// glide 加載圖檔大小 0~1之間 如設定 .glideOverride()無效
.setOutputCameraPath("/CustomPath")// 自定義拍照儲存路徑,可不填
.enableCrop()// 是否裁剪 true or false
.compress()// 是否壓縮 true or false
.glideOverride()// int glide 加載寬高,越小圖檔清單越流暢,但會影響清單圖檔浏覽的清晰度
.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定義
.hideBottomControls()// 是否顯示uCrop工具欄,預設不顯示 true or false
.isGif()// 是否顯示gif圖檔 true or false
.compressSavePath(getPath())//壓縮圖檔儲存位址
.freeStyleCropEnabled()// 裁剪框是否可拖拽 true or false
.circleDimmedLayer()// 是否圓形裁剪 true or false
.showCropFrame()// 是否顯示裁剪矩形邊框 圓形裁剪時建議設為false true or false
.showCropGrid()// 是否顯示裁剪矩形網格 圓形裁剪時建議設為false true or false
.openClickSound()// 是否開啟點選聲音 true or false
.selectionMedia()// 是否傳入已選圖檔 List<LocalMedia> list
.previewEggs()// 預覽圖檔時 是否增強左右滑動圖檔體驗(圖檔滑動一半即可看到上一張是否選中) true or false
.cropCompressQuality()// 裁剪壓縮品質 預設90 int
.minimumCompressSize(100)// 小于100kb的圖檔不壓縮
.synOrAsy(true)//同步true或異步false 壓縮 預設同步
.cropWH()// 裁剪寬高比,設定如果大于圖檔本身寬高則無效 int
.rotateEnabled() // 裁剪是否可旋轉圖檔 true or false
.scaleEnabled()// 裁剪是否可放大縮小圖檔 true or false
.videoQuality()// 視訊錄制品質 0 or 1 int
.videoMaxSecond(15)// 顯示多少秒以内的視訊or音頻也可适用 int
.videoMinSecond(10)// 顯示多少秒以内的視訊or音頻也可适用 int
.recordVideoSecond()//視訊秒數錄制 預設60s int
.isDragFrame(false)// 是否可拖動裁剪框(固定)
.forResult(PictureConfig.CHOOSE_REQUEST);//結果回調onActivityResult code
複制
內建方式
compile引入
dependencies {
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3'
}
複制
build.gradle加入
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}
複制
使用
使用非常簡單,你想要的基本上都有
package com.yechaoa.pictureselectordemo;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.permissions.Permission;
import com.luck.picture.lib.permissions.RxPermissions;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.functions.Consumer;
public class MainActivity extends AppCompatActivity {
private int maxSelectNum = 9;
private List<LocalMedia> selectList = new ArrayList<>();
private GridImageAdapter adapter;
private RecyclerView mRecyclerView;
private PopupWindow pop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recycler);
initWidget();
}
private void initWidget() {
FullyGridLayoutManager manager = new FullyGridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(manager);
adapter = new GridImageAdapter(this, onAddPicClickListener);
adapter.setList(selectList);
adapter.setSelectMax(maxSelectNum);
mRecyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new GridImageAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position, View v) {
if (selectList.size() > 0) {
LocalMedia media = selectList.get(position);
String pictureType = media.getPictureType();
int mediaType = PictureMimeType.pictureToVideo(pictureType);
switch (mediaType) {
case 1:
// 預覽圖檔 可自定長按儲存路徑
//PictureSelector.create(MainActivity.this).externalPicturePreview(position, "/custom_file", selectList);
PictureSelector.create(MainActivity.this).externalPicturePreview(position, selectList);
break;
case 2:
// 預覽視訊
PictureSelector.create(MainActivity.this).externalPictureVideo(media.getPath());
break;
case 3:
// 預覽音頻
PictureSelector.create(MainActivity.this).externalPictureAudio(media.getPath());
break;
}
}
}
});
}
private GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {
@SuppressLint("CheckResult")
@Override
public void onAddPicClick() {
//擷取寫的權限
RxPermissions rxPermission = new RxPermissions(MainActivity.this);
rxPermission.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) {
if (permission.granted) {// 使用者已經同意該權限
//第一種方式,彈出選擇和拍照的dialog
showPop();
//第二種方式,直接進入相冊,但是 是有拍照得按鈕的
// showAlbum();
} else {
Toast.makeText(MainActivity.this, "拒絕", Toast.LENGTH_SHORT).show();
}
}
});
}
};
private void showAlbum() {
//參數很多,根據需要添加
PictureSelector.create(MainActivity.this)
.openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、圖檔.ofImage()、視訊.ofVideo()、音頻.ofAudio()
.maxSelectNum(maxSelectNum)// 最大圖檔選擇數量
.minSelectNum(1)// 最小選擇數量
.imageSpanCount(4)// 每行顯示個數
.selectionMode(PictureConfig.MULTIPLE)// 多選 or 單選PictureConfig.MULTIPLE : PictureConfig.SINGLE
.previewImage(true)// 是否可預覽圖檔
.isCamera(true)// 是否顯示拍照按鈕
.isZoomAnim(true)// 圖檔清單點選 縮放效果 預設true
//.setOutputCameraPath("/CustomPath")// 自定義拍照儲存路徑
.enableCrop(true)// 是否裁剪
.compress(true)// 是否壓縮
//.sizeMultiplier(0.5f)// glide 加載圖檔大小 0~1之間 如設定 .glideOverride()無效
.glideOverride(160, 160)// glide 加載寬高,越小圖檔清單越流暢,但會影響清單圖檔浏覽的清晰度
.withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定義
//.selectionMedia(selectList)// 是否傳入已選圖檔
//.previewEggs(false)// 預覽圖檔時 是否增強左右滑動圖檔體驗(圖檔滑動一半即可看到上一張是否選中)
//.cropCompressQuality(90)// 裁剪壓縮品質 預設100
//.compressMaxKB()//壓縮最大值kb compressGrade()為Luban.CUSTOM_GEAR有效
//.compressWH() // 壓縮寬高比 compressGrade()為Luban.CUSTOM_GEAR有效
//.cropWH()// 裁剪寬高比,設定如果大于圖檔本身寬高則無效
.rotateEnabled(false) // 裁剪是否可旋轉圖檔
//.scaleEnabled()// 裁剪是否可放大縮小圖檔
//.recordVideoSecond()//錄制視訊秒數 預設60s
.forResult(PictureConfig.CHOOSE_REQUEST);//結果回調onActivityResult code
}
private void showPop() {
View bottomView = View.inflate(MainActivity.this, R.layout.layout_bottom_dialog, null);
TextView mAlbum = bottomView.findViewById(R.id.tv_album);
TextView mCamera = bottomView.findViewById(R.id.tv_camera);
TextView mCancel = bottomView.findViewById(R.id.tv_cancel);
pop = new PopupWindow(bottomView, -1, -2);
pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
pop.setOutsideTouchable(true);
pop.setFocusable(true);
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 0.5f;
getWindow().setAttributes(lp);
pop.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = 1f;
getWindow().setAttributes(lp);
}
});
pop.setAnimationStyle(R.style.main_menu_photo_anim);
pop.showAtLocation(getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_album:
//相冊
PictureSelector.create(MainActivity.this)
.openGallery(PictureMimeType.ofImage())
.maxSelectNum(maxSelectNum)
.minSelectNum(1)
.imageSpanCount(4)
.selectionMode(PictureConfig.MULTIPLE)
.forResult(PictureConfig.CHOOSE_REQUEST);
break;
case R.id.tv_camera:
//拍照
PictureSelector.create(MainActivity.this)
.openCamera(PictureMimeType.ofImage())
.forResult(PictureConfig.CHOOSE_REQUEST);
break;
case R.id.tv_cancel:
//取消
//closePopupWindow();
break;
}
closePopupWindow();
}
};
mAlbum.setOnClickListener(clickListener);
mCamera.setOnClickListener(clickListener);
mCancel.setOnClickListener(clickListener);
}
public void closePopupWindow() {
if (pop != null && pop.isShowing()) {
pop.dismiss();
pop = null;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
List<LocalMedia> images;
if (resultCode == RESULT_OK) {
if (requestCode == PictureConfig.CHOOSE_REQUEST) {// 圖檔選擇結果回調
images = PictureSelector.obtainMultipleResult(data);
selectList.addAll(images);
//selectList = PictureSelector.obtainMultipleResult(data);
// 例如 LocalMedia 裡面傳回三種path
// 1.media.getPath(); 為原圖path
// 2.media.getCutPath();為裁剪後path,需判斷media.isCut();是否為true
// 3.media.getCompressPath();為壓縮後path,需判斷media.isCompressed();是否為true
// 如果裁剪并壓縮了,以取壓縮路徑為準,因為是先裁剪後壓縮的
adapter.setList(selectList);
adapter.notifyDataSetChanged();
}
}
}
}
複制