本文概述
- 1.配置依赖关系和库
- 2.准备资源字符串
- 3.创建GifSizeFilter类
- 4.创建Glide 4图像引擎
- 5.创建应用程序布局
- 6.基本例子
- 完整的例子
- 在活动或片段中使用它
- 选择包括JPEG, PNG, GIF的图像和包括MPEG, MP4的视频
- 应用不同的主题, 包括两个内置主题和自定义主题
- 不同的图像加载器
- 定义自定义过滤规则
- 进一步了解自己
1.配置依赖关系和库你将需要包括并更新所有Android支持库, 以匹配项目的compileSdkVersion。在这种情况下, 我们使用的compileSdkVersion设置为28的新Android项目, 因此我们的库将使用Matisse所需的所有android支持库的版本28。还包括Glide引擎和Matisse库。截止到本文发布之日, 我们正在使用每个库的最新版本:
dependencies {implementation 'com.android.support:appcompat-v7:28.0.0'implementation 'com.android.support:recyclerview-v7:28.0.0'implementation 'com.android.support:animated-vector-drawable:28.0.0'implementation 'com.android.support:support-media-compat:28.0.0'implementation 'com.android.support.constraint:constraint-layout:1.1.3'implementation 'com.android.support:support-v4:28.0.0'implementation 'com.github.bumptech.glide:glide:4.9.0'annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'implementation 'com.zhihu.android:matisse:0.5.2-beta3'}
保存更改并同步项目。安装库之后, 我们将可以在你的项目中继续使用该库。有关Matisse的更多信息, 请访问此处的Github官方存储库, 或有关Glide的更多信息, 也访问其在Github的存储库。
2.准备资源字符串在你的app / src / res / values / strings.xml文件中, 添加以下资源:
<
resources>
<
string name="error_gif">
x or y bound size should be at least %1$dpx and file size should be no more than %2$sM<
/string>
<
/resources>
在同一目录中, 创建具有以下内容的dimens.xml文件:
<
?xml version="1.0" encoding="utf-8"?>
<
!--Copyright 2017 Zhihu Inc.Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.-->
<
resources>
<
dimen name="grid_expected_size">
120dp<
/dimen>
<
dimen name="item_margin_horizontal">
24dp<
/dimen>
<
dimen name="item_margin_vertical">
8dp<
/dimen>
<
/resources>
3.创建GifSizeFilter类【如何使用适用于Android的Matisse库和Glide 4创建带有预览的图像/视频选择器】在选择器初始化期间, 我们将定义GifSizeFilter的实例作为选择器的图像过滤器, 该类将定义图像的大小和操作系统, 因此继续在你的应用中创建一个新类, 即GifSizeFilter。具有以下内容的java:
package com.yourcompany.yourapp;
import android.content.Context;
import android.graphics.Point;
import com.zhihu.matisse.MimeType;
import com.zhihu.matisse.filter.Filter;
import com.zhihu.matisse.internal.entity.IncapableCause;
import com.zhihu.matisse.internal.entity.Item;
import com.zhihu.matisse.internal.utils.PhotoMetadataUtils;
import java.util.HashSet;
import java.util.Set;
class GifSizeFilter extends Filter {private int mMinWidth;
private int mMinHeight;
private int mMaxSize;
GifSizeFilter(int minWidth, int minHeight, int maxSizeInBytes) {mMinWidth = minWidth;
mMinHeight = minHeight;
mMaxSize = maxSizeInBytes;
}@Overridepublic Set<
MimeType>
constraintTypes() {return new HashSet<
MimeType>
() {{add(MimeType.GIF);
}};
}@Overridepublic IncapableCause filter(Context context, Item item) {if (!needFiltering(context, item))return null;
Point size = PhotoMetadataUtils.getBitmapBound(context.getContentResolver(), item.getContentUri());
if (size.x <
mMinWidth || size.y <
mMinHeight || item.size >
mMaxSize) {return new IncapableCause(IncapableCause.DIALOG, context.getString(R.string.error_gif, mMinWidth, String.valueOf(PhotoMetadataUtils.getSizeInMB(mMaxSize))));
}return null;
}}
4.创建Glide 4图像引擎图像/视频选择器使用Glide库(一种用于Android的快速有效的开源媒体管理和图像加载框架)将媒体解码, 内存和磁盘缓存以及资源池包装到一个简单易用的界面中。在选择器初始化期间, 我们将Glide 4引擎的实例定义为首选图像引擎, 因此继续在你的应用中创建一个新类, 即Glide4Engine.java, 其内容如下:
package com.yourcompany.yourapp;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.request.RequestOptions;
import com.zhihu.matisse.engine.ImageEngine;
/** * {@link ImageEngine} implementation using Glide. */public class Glide4Engine implements ImageEngine {@Overridepublic void loadThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) {Glide.with(context).asBitmap() // some .jpeg files are actually gif.load(uri).apply(new RequestOptions().override(resize, resize).placeholder(placeholder).centerCrop()).into(imageView);
}@Overridepublic void loadGifThumbnail(Context context, int resize, Drawable placeholder, ImageView imageView, Uri uri) {Glide.with(context).asBitmap() // some .jpeg files are actually gif.load(uri).apply(new RequestOptions().override(resize, resize).placeholder(placeholder).centerCrop()).into(imageView);
}@Overridepublic void loadImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) {Glide.with(context).load(uri).apply(new RequestOptions().override(resizeX, resizeY).priority(Priority.HIGH).fitCenter()).into(imageView);
}@Overridepublic void loadGifImage(Context context, int resizeX, int resizeY, ImageView imageView, Uri uri) {Glide.with(context).asGif().load(uri).apply(new RequestOptions().override(resizeX, resizeY).priority(Priority.HIGH).fitCenter()).into(imageView);
}@Overridepublic boolean supportAnimatedGif() {return true;
}}
5.创建应用程序布局在此应用程序中, 我们的布局将非常简单, 但是它基于约束布局, 因此你可以根据需要更改它, 只需在activity_main.xml文件中添加带有id按钮的按钮即可。我们的布局如下所示:
<
?xml version="1.0" encoding="utf-8"?>
<
android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity">
<
Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="49dp"android:text="Pick a file(s)"tools:layout_editor_absoluteX="16dp"tools:layout_editor_absoluteY="16dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>
<
/android.support.constraint.ConstraintLayout>
主要思想是有一个按钮, 当单击它时会打开图像选择器。
6.基本例子使该选择器工作所需的逻辑如下:声明2个类可访问变量, 这些变量将包含活动结果, 权限等的随机标识码, 以及一个Uri的列表变量, 该变量将分别包含用户选择的文件。我们有一个按钮, 因此我们将添加一个onClick侦听器, 该侦听器将使用自定义选项(你??可以根据需要对其进行自定义)静态调用Matisse对话框的实例, 例如, 我们将允许选择所有类型的图像并设置一个最多可选择9个文件。如前所述, 我们的示例将使用Glide 4 Engine, 因此你将需要定义一个新实例, 并将其作为Matisse的imageEngine方法的参数提供。
这将打开对话框, 用户将可以在对话框中选择图像。用户单击” 确定” 后, 将取决于你如何处理主要活动的onActivityResult回调上的接收数据。在我们的例子中, 我们将只在日志中显示数据:
请注意, 该示例不处理权限, 你将需要自己执行此操作。在完整的示例中检查权限。
// Random code that identifies the result of the pickerpublic static final int PICKER_REQUEST_CODE = 1;
// List that will contain the selected files/videosList<
Uri>
mSelected;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {// When the button is clicked, open the Matisse dialog to pick images !Matisse.from(MainActivity.this).choose(MimeType.ofAll()).countable(true).maxSelectable(9).addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K)).gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size)).restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED).thumbnailScale(0.85f).imageEngine(new Glide4Engine()).forResult(PICKER_REQUEST_CODE);
}});
}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICKER_REQUEST_CODE &
&
resultCode == RESULT_OK) {mSelected = Matisse.obtainResult(data);
// Display in the logs the selected items.// Outputs something like:// D/Matisse: mSelected: [//content://media/external/images/media/26263, //content://media/external/images/media/26264, //content://media/external/images/media/26261// ]Log.d("Matisse", "mSelected: " + mSelected);
}}
完整的例子你将需要在AndroidManifest.xml文件中处理READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的权限:
<
uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
但是, 对于Android 6+而言, 这还不够, 因为你将需要在运行时上请求权限, 以下示例描述了具有单个活动的功能齐全的应用程序, 处理了权限并应用了本文中提到的所有步骤:
package com.yourcompany.yourapp;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.zhihu.matisse.Matisse;
import com.zhihu.matisse.MimeType;
import com.zhihu.matisse.filter.Filter;
import java.util.List;
public class MainActivity extends AppCompatActivity {public static final int PICKER_REQUEST_CODE = 1;
// List that will contain the selected files/videosList<
Uri>
mSelected;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {String[] PERMISSIONS = {android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE};
if(hasPermissions(MainActivity.this, PERMISSIONS)){ShowPicker();
}else{ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, PICKER_REQUEST_CODE);
}}});
}/*** Method that displays the image/video chooser.*/public void ShowPicker(){Matisse.from(MainActivity.this).choose(MimeType.ofAll()).countable(true).maxSelectable(9).addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K)).gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size)).restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED).thumbnailScale(0.85f).imageEngine(new Glide4Engine()).forResult(PICKER_REQUEST_CODE);
}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICKER_REQUEST_CODE &
&
resultCode == RESULT_OK) {mSelected = Matisse.obtainResult(data);
Log.d("Matisse", "mSelected: " + mSelected);
}}/*** Helper method that verifies whether the permissions of a given array are granted or not.** @param context* @param permissions* @return {Boolean}*/public static boolean hasPermissions(Context context, String... permissions) {if (context != null &
&
permissions != null) {for (String permission : permissions) {if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {return false;
}}}return true;
}/*** Callback that handles the status of the permissions request.** @param requestCode* @param permissions* @param grantResults*/@Overridepublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {switch (requestCode) {case PICKER_REQUEST_CODE: {// If request is cancelled, the result arrays are empty.if (grantResults.length >
0 &
&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {Toast.makeText(MainActivity.this, "Permission granted! Please click on pick a file once again.", Toast.LENGTH_SHORT).show();
} else {Toast.makeText(MainActivity.this, "Permission denied to read your External storage :(", Toast.LENGTH_SHORT).show();
}return;
}}}}
编码愉快!
推荐阅读
- 如何使用存储选择器库在Android +4.4中使用存储选择器创建文件/文件夹选择器
- Kint(现代而强大的PHP调试助手)
- Android错误(找不到与给定名称匹配的资源(在”icon”处,值为”@drawable/icon”))
- PHP调试栏(显示任何PHP项目中应用程序任何部分的概要分析数据)
- JSPaint(出色的基于Web的Microsoft Paint重制(95、98,XP版))
- Winamp2-js(在HTML5和Javascript中对Winamp 2.9的重新实现)
- Xenia(Xbox 360模拟器研究项目)
- Electron小提琴(在本地构建和玩小型Electron实验)
- RPCS3(实验性开源Sony PlayStation 3仿真器)