
知乎 Matisse 全功能解析:Android 开发者必看的图片与视频选择器指南
前言
在 Android 应用开发中,从相册选择图片/视频 是几乎所有内容型应用都会遇到的需求,例如:
- 社交 App 发布动态上传图片
- IM 应用发送图片/视频
- 电商 App 上传商品照片
- 企业级应用拍照并上传材料
虽然原生 API 也能实现媒体选择,但界面复杂、设备兼容性差,图片压缩/旋转/格式解析都需开发者自行处理。
为此,知乎开源了一个极其优秀的媒体选择器库 —— Matisse。

Matisse 是一个高度易用、可扩展、风格统一、兼容性很好的媒体选择框架,支持:
- 图片选择
- 视频选择
- 混合选择
- 多选
- 拍照
- 过滤器
- 原图模式
- 大图预览
- 自定义图片加载引擎(Glide/Coil/Picasso)
本文将为你完整解析 Matisse 的功能、使用方式、源码结构及最佳实践,从入门到进阶,一文掌握。
1. Matisse 是什么?
Matisse 是知乎团队开发的 Android 媒体选择器,提供统一、优雅的 UI,并极大简化媒体读取流程。
github地址:https://github.com/zhihu/Matisse
它的优点包括:
统一的媒体选择 UI
无需自己写 Adapter、Loader、Thumbnail,直接使用 Material 风格界面。
支持图片、视频、混合选择
可自行决定支持哪些 MIME 类型。
支持多选、计数模式
如朋友圈发动态那样的“1/9、2/9”。
支持从相册直接调用“拍一张”
并支持 FileProvider 权限适配。
极强的扩展性
可接入 Glide、Picasso、Coil 等任意图片库。
完整的结果回调
提供 Uri、绝对路径、Original 状态,方便上传处理。
简而言之,如果你需要一个既好看又好用、可定制性强的媒体选择器,Matisse 是最成熟的选择之一。
2. 如何集成 Matisse?
Gradle 添加依赖:
repositories {
jcenter()
}
dependencies {
implementation 'com.zhihu.android:matisse:$latest_version'
}
如果使用 其它版本(fork 版本),保持 API 接口一致。
另外,使用拍照功能时必须注册 FileProvider:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
3. 基础使用示例(最常用的媒体选择方式)
调用 Matisse:
Matisse.from(activity)
.choose(MimeType.ofImage())
.countable(true)
.maxSelectable(9)
.imageEngine(new GlideEngine())
.forResult(REQUEST_CODE_CHOOSE);
在 onActivityResult 接收结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {
List<Uri> uris = Matisse.obtainResult(data);
List<String> paths = Matisse.obtainPathResult(data);
}
}
到这里,你已经可以像微信公众号、微博、知乎一样选择图片了。
4. 主题与 UI 配置
Matisse 内置两种主题:
系统默认主题(亮色)
.theme(R.style.Matisse_Zhihu)

Dracula(暗色主题)
.theme(R.style.Matisse_Dracula)

想要自定义?
直接重写主题中的:
- Toolbar 颜色
- Bottom Action Bar 颜色
- 状态栏模式(亮/暗)
完全可高度定制 UI 风格。
示例:
//====================================== Theme Zhihu ===========================================
<style name="Matisse.Zhihu" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/zhihu_primary</item>
<item name="colorPrimaryDark">@color/zhihu_primary_dark</item>
<item name="toolbar">@style/Toolbar.Zhihu</item>
<item name="album.dropdown.title.color">@color/zhihu_album_dropdown_title_text</item>
<item name="album.dropdown.count.color">@color/zhihu_album_dropdown_count_text</item>
<item name="album.element.color">@android:color/white</item>
<item name="album.thumbnail.placeholder">@color/zhihu_album_dropdown_thumbnail_placeholder</item>
<item name="album.emptyView">@drawable/ic_empty_zhihu</item>
<item name="album.emptyView.textColor">@color/zhihu_album_empty_view</item>
<item name="item.placeholder">@color/zhihu_item_placeholder</item>
<item name="item.checkCircle.backgroundColor">@color/zhihu_item_checkCircle_backgroundColor</item>
<item name="item.checkCircle.borderColor">@color/zhihu_item_checkCircle_borderColor</item>
<item name="page.bg">@color/zhihu_page_bg</item>
<item name="bottomToolbar.bg">@color/zhihu_bottom_toolbar_bg</item>
<item name="bottomToolbar.preview.textColor">@color/zhihu_bottom_toolbar_preview</item>
<item name="bottomToolbar.apply.textColor">@color/zhihu_bottom_toolbar_apply</item>
<item name="preview.bottomToolbar.back.textColor">@color/zhihu_preview_bottom_toolbar_back_text</item>
<item name="preview.bottomToolbar.apply.textColor">@color/zhihu_preview_bottom_toolbar_apply</item>
<item name="listPopupWindowStyle">@style/Popup.Zhihu</item>
<item name="capture.textColor">@color/zhihu_capture</item>
</style>
5. 拍照功能(Capture)
Matisse 提供一个“拍照”按钮,会启动系统相机。
启用拍照:
.capture(true)
.captureStrategy(new CaptureStrategy(true, applicationId + ".fileprovider"))
各fork分支大同小异
.capture(AlbumMediaLoader.Capture.Image)
它会在相册第一行添加:
拍一张
点击后打开系统相机,照片自动写入 FileProvider 目录。
注意
Matisse 不提供自定义相机 UI,仅调用系统相机。
6. 拍照存储策略 CaptureStrategy
new CaptureStrategy(
true, // 是否公开存储目录(public)
applicationId + ".fileprovider",
"Pictures" // 可选,自定义目录
)
你可以控制:
- 是否写入公共存储
- 是否需要 Uri 权限
- 拍照保存的路径
非常适合需要持久化图片的业务。
7. 媒体 Engine:Glide / Picasso / Coil
Matisse 不直接加载图片,可使用三方库。
使用 Glide:
.imageEngine(new GlideEngine())
也可以实现自定义 Engine:
public class CoilEngine implements ImageEngine {
// 自己实现 loadThumbnail、loadGif 等方法
}
优点:
- Matisse 不绑定任何图片库
- 项目自己决定使用 Glide / Picasso / Fresco / Coil
8. 原图模式(Original)
开启“原图”按钮:
.originalEnable(true)
.maxOriginalSize(10) // 单个文件最大 10MB
界面底部会出现:
- 原图 checkbox
- 原图大小提示
如果文件大小超过设定值,将无法选择。
结果中会标记:
Matisse.obtainOriginalState(data);
9. Filter 过滤器(自定义筛选)
Matisse 提供 Filter 接口来过滤媒体。
示例:过滤大于 5MB 的 GIF
.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
你可以自定义:
- 图片大小限制
- 分辨率限制
- 视频时长限制
- 禁用 GIF
示例:禁止长图(高度 > 4000px)
public class LongImageFilter extends Filter {
@Override
public Set<MimeType> constraintTypes() {
return MimeType.ofImage();
}
@Override
public boolean filter(Context context, Item item) {
return item.getHeight() > 4000;
}
}
10. 视频选择功能
Matisse 支持读取视频文件,包含:
- 缩略图
- 时长显示
- 点击播放(系统播放器)
配置示例:
.choose(MimeType.ofVideo())
.maxSelectable(2)
也支持混合选择:
.choose(MimeType.ofAll())
.maxSelectablePerMediaType(3, 1) // 图片最多3,视频最多1
11. orientation 屏幕方向锁定
避免进入相册后屏幕旋转导致 Activity 重建,可以:
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
常用取值:
- PORTRAIT(竖屏)
- LANDSCAPE(横屏)
- SENSOR(自动旋转)
如果你的 App 是横屏游戏或相机 App,这个非常关键(能避免 CameraAccessException)。
12. 支持的返回结果类型
回调中可获得:
Uri 列表(推荐 Android 10+)
Matisse.obtainResult(data)
绝对路径(Android 10 需要额外权限)
Matisse.obtainPathResult(data)
原图选择状态
Matisse.obtainOriginalState(data)
这些足够用于图片上传、压缩等业务逻辑。
13. 完整的媒体信息 Item 结构(高级扩展)
Matisse 内部使用 Item 存储媒体信息,包含:
- id
- MIME Type
- Uri
- Path
- 宽/高
- 文件大小
- 视频时长
- 是否 GIF
可以用来做:
- 大图预览
- 视频封面提取
- 文件验证
- 压缩逻辑判断
14. Matisse 的内部架构(深入理解)
Matisse 的结构大致分为:
MatisseActivity
主入口界面,展示文件夹/媒体列表。
MediaStoreCompat
封装拍照、Uri、FileProvider 写入行为。
AlbumCollection
负责从 MediaStore 加载媒体。
SelectedItemCollection
维持当前选中的媒体状态。
PreviewActivity / PreviewItemFragment
大图预览界面。
Filter
媒体过滤逻辑。
ImageEngine
图片加载引擎。
架构非常清晰,可任意扩展 UI 或行为。
15. 常见问题与实践建议
Android 13 权限适配
需要手动申请:
READ_MEDIA_IMAGES
READ_MEDIA_VIDEO
避免 CameraAccessException(相机页 → Matisse → 返回)
如果你的 Activity 是横屏相机页面,请务必:
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
否则 Activity 重建会导致 Camera 重启冲突。
GlideEngine 使用错误可能造成大图加载失败
确保使用:
Glide.with(context)
而不是 applicationContext。
不显示 GIF 预览?
需要在 choose 中加 GIF:
.choose(MimeType.of(MimeType.JPEG, MimeType.GIF))
16. 完整 Matisse 配置示例(可直接使用)
Matisse.from(activity)
.choose(MimeType.ofAll()) // 图片 + 视频
.theme(R.style.Matisse_Dracula)
.countable(true)
.maxSelectablePerMediaType(9, 1) // 图片最多9,视频最多1
.capture(true)
.captureStrategy(new CaptureStrategy(true, applicationId + ".fileprovider"))
.imageEngine(new GlideEngine())
.originalEnable(true)
.maxOriginalSize(10)
.addFilter(new LongImageFilter())
.showSingleMediaType(false)
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.forResult(REQUEST_CODE_PICK);
这是适用于大多数 App 的配置。


3357





