圖片選擇器 Matisse 在 6.0 以上手機使用相機以及選擇圖片過濾小圖功能
阿新 • • 發佈:2019-01-30
2018-7-23 更新
Matisse 中使用 Filter 過濾圖片大小等操作
Filter 過濾器,Matisse 中這樣描述:Filter for choosing a {@link Item}. You can add multiple Filters through 也就是在你選擇圖片的時候過濾掉你不想選擇的內容。
例如:網上常見的過濾gif
功能,還有我這裡說明的過濾圖片大小
功能.
首先建立一個子類,繼承 Matisse
中使用 Filter
public class MiniSizeFilter extends Filter {
private int mMinWidth;
private int mMinHeight;
private int mMaxSize;
public MiniSizeFilter(int minWidth, int minHeight, int maxSizeInBytes) {
mMinWidth = minWidth;
mMinHeight = minHeight;
mMaxSize = maxSizeInBytes;
}
/**
* 約束的圖片型別
* @return
*/
@Override
protected Set<MimeType> constraintTypes() {
return EnumSet.of(MimeType.JPEG, MimeType.PNG, MimeType.BMP, MimeType.WEBP);
}
@Override
public IncapableCause filter(Context context, Item item) {
if (!needFiltering(context, item)){
return null;
}
Point size = PhotoMetadataUtils.getBitmapBound(context.getContentResolver(), item.getContentUri());
// Log.e(TAG, "filter: mimeType--------->"+item.mimeType);
// Log.e(TAG, "filter: describeContents--------->"+item.describeContents());
// Log.e(TAG, "filter: duration--------->"+item.duration);
// Log.e(TAG, "filter: getContentUri--------->"+item.getContentUri());
// Log.e(TAG, "filter: id--------->"+item.id);
// 圖片的大小
// Log.e(TAG, "filter: size--------->"+item.size);
// Log.e(TAG, "filter: uri--------->"+item.uri);
// 圖片的寬高
// Log.e(TAG, "filter: size.x--------->"+size.x );
// Log.e(TAG, "filter: size.y--------->"+size.y );
if (size.x < mMinWidth || size.y < mMinHeight || item.size > mMaxSize) {
// IncapableCause.TOAST 表示 Toast 提示,它有三個選擇:{TOAST, DIALOG, NONE}
return new IncapableCause(IncapableCause.TOAST, context.getString(R.string.image_size_to_small, mMinWidth,
String.valueOf(PhotoMetadataUtils.getSizeInMB(mMaxSize))));
}
return null;
}
}
使用方式如下:
Matisse.from(MainActivity.this)
...
.addFilter(new MiniSizeFilter(320, 320, 5 * Filter.K * Filter.K)) // 控制寬高為320*320 以上,大小為 50M 以下
.forResult(REQUEST_CODE_CHOOSE);
以上為2018-7-23更新
首發地址:dongxi520.com
需求:實現一個圖片選擇器,能選擇本地圖片和拍照
拿到需求,第一個想法就是看自己在規定時間上能否又快又好的實現。顯然是不能( 。。),現在那麼多前輩都把輪子都造好了,我們直接拼裝不久可以了嗎?目前為止,我還是這樣,等功能深厚成為前輩了再擼幾個輪子給後輩使用,這些都是後話,先實現這個需求吧。
先去GitHub搜尋一圈圖片選擇器,發現知乎開源的Matisse傢伙長的挺好看的,就選它了。使用步驟看GitHub的,官方的才是最正確的使用姿勢。Matisse
官網的使用方式 預設是不開啟拍照功能的,因此需要拍照功能的可以這麼寫
Matisse.from(PublishActivity.this)
.choose(MimeType.allOf()) // 選擇 mime 的型別
.countable(true) // 顯示選擇的數量
.capture(true) // 開啟相機,和 captureStrategy 一併使用否則報錯
.captureStrategy(new CaptureStrategy(true,"com.meiqu.pianxin.ui.publish.MyFileProvider")) // 拍照的圖片路徑
.theme(R.style.Matisse_Dracula) // 黑色背景
.maxSelectable(9) // 圖片選擇的最多數量
.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size)) // 列表中顯示的圖片大小
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
.thumbnailScale(0.85f) // 縮圖的比例
.imageEngine(new GlideEngine()) // 使用的圖片載入引擎
.forResult(REQUEST_CODE_CHOOSE); // 設定作為標記的請求碼,返回圖片時使用
captureStrategy(new CaptureStrategy(true,"com.meiqu.pianxin.ui.publish.MyFileProvider"))
主要是告知系統拍照的圖片儲存位置- 第二個引數是自己實現繼承FileProvider類的一個空類,需要在manifest檔案中新增如下程式碼
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.meiqu.pianxin.ui.publish.MyFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths"/>
</provider>
- android:resource=”@xml/filepaths” 是在res/xml 目錄下的建立的檔案filepaths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--代表外部儲存區域的根目錄下的檔案 Environment.getExternalStorageDirectory()/DCIM/camerademo目錄-->
<external-path name="mq_DCIM" path="DCIM/camerademo" />
<!--代表外部儲存區域的根目錄下的檔案 Environment.getExternalStorageDirectory()/Pictures/camerademo目錄-->
<external-path name="mq_Pictures" path="Pictures/camerademo" />
<!--代表app 私有的儲存區域 Context.getFilesDir()目錄下的images目錄 /data/user/0/com.hm.camerademo/files/images-->
<files-path name="mq_private_files" path="images" />
<!--代表app 私有的儲存區域 Context.getCacheDir()目錄下的images目錄 /data/user/0/com.hm.camerademo/cache/images-->
<cache-path name="mq_private_cache" path="images" />
<!--代表app 外部儲存區域根目錄下的檔案 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)目錄下的Pictures目錄-->
<external-files-path name="mq_external_files" path="Pictures" />
<!--代表app 外部儲存區域根目錄下的檔案 Context.getExternalCacheDir目錄下的images目錄-->
<external-cache-path name="mq_external_cache" path="" />
<root-path name="mq_external_cache" path="" />
</paths>
以上使用在 5.0 以下的手機是沒毛病的,在 6.0 這個動態許可權的控制下就有些問題了
6.0 以上使用 Matisse 的正確姿勢
Matisse 和 PermissionsDispatcher 的使用姿勢
Matisse 需要用到相機和讀寫本地資料的許可權
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.Manifest.permission.READ_PHONE_STATE" />
所以在呼叫了這些許可權的地方是使用 PermissionsDispatcher 去動態設定,看PermissionsDispatcher 官網介紹
我在實際中使用
步驟:
- 在Activity或者Fragment上新增 @RuntimePermissions
- 在用到許可權的方法( 例如:void initData(),不能加上 private 修飾)名上新增@NeedsPermission(Manifest.permission.READ_PHONE_STATE)
- 重寫onRequestPermissionsResult方法,MainActivityPermissionsDispatcher.onRequestPermissionsResult(MainActivity.this, requestCode, grantResults);
- 在onCreate方法呼叫MainActivityPermissionsDispatcher.initDataWithCheck(MainActivity.this);
例項:
@RuntimePermissions // 必須新增
public class MainActivity extends AppCompatActivity {
...
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
....
MainActivityPermissionsDispatcher.initDataWithCheck(MainActivity.this);
....
}
@NeedsPermission(Manifest.permission.READ_PHONE_STATE) // 必須新增
void initData() { // 會呼叫使用者資訊許可權
DataCenter dc = DataCenter.getInstance();
dc.initDataCenter(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
MainActivityPermissionsDispatcher.onRequestPermissionsResult(MainActivity.this, requestCode, grantResults);
}
}