效果图:
Android 选择图片、上传图片之Matisse_matisseAndroid 选择图片、上传图片之Matisse_android上传图片_02Android 选择图片、上传图片之Matisse_matisse_03Android 选择图片、上传图片之Matisse_matisse_04

就目前效果图来看,好像也没什么毛病哈,其实我这个集成的过程是有点坎坷的。
而且,功能也不算是很齐全吧…主要体现在以下几个点

  • 没有回调之后的预览
  • 选择之后不能删除已选
  • 已选择的图片再次选择不能带过去
  • 剪裁
  • 压缩
  • 权限
  • Glide版本过低

但是,也是有特点的

  • MD风格
  • 白天模式和夜间模式

其他与同类相比也真的没什么了,唯一背书 就是知乎团队出的呗。。
相比之下,昨天出的​Android 选择图片、上传图片之PictureSelector就更加友好和人性化了。

下面来说说集成遇到的问题以及解决方案。

gayhub:​​https://github.com/zhihu/Matisse​

集成

Gradle:

repositories {
jcenter()
}

dependencies {
compile 'com.zhihu.android:matisse:0.4.3'
}

releases最新是v0.5.0-beta3的,本文还是基于官方文档0.4.3的版本

你以为这样就可以使用了吗,nonono,权限需要动态获取,你还需要​​RxPermissions​​或者其他权限库,或者自己封装

compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'

这就完了吗,no,你还需要​​rxjava​

compile "io.reactivex.rxjava2:rxjava:2.1.9"

现在总可以了吧,依然nonono,如果你项目集成了​​Glide​​​,还是会报错,我在用的Glide版本是4.6.1的,Matisse中集成的是3.7.0的,是有区别的,具体你可以看这里 带你全面了解Glide 4的用法​,你也可以用​​Picasso​​。

会报异常

java.lang.NoSuchMethodError: com.bumptech.glide.RequestManager.load

解决方案就是重新自定义图片加载方式​​GlideEngine​​​,具体可以看这里Matisse 与 Glide – java.lang.NoSuchMethodError: com.bumptech.glide.RequestManager.load。

到这里你以为就ok了吗,还是nonono,还是会报异常,因为两个版本会冲突啊

java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper

解决方案看这里java.lang.NoClassDefFoundError: android.support.v4.animation.AnimatorCompatHelper

Matisse:爱我你怕了吗

终于可以使用了,哇的哭出声

使用

你以为集成都这么坎坷了,使用应该很方便吧,no啊大胸弟,
虽然集成之前我看到150+的Issues有点头皮发麻,果然没让我失望,坎坷的路还长着呢。

最快的方式集成第三方有两种,1.看官方文档,2.看例子。

你以为从sample中copy copy代码,导下包就能跑起来了吗,nonono

选择器不光是有图片的吧,你可能还有gif和视频啊,所以在配置的时候你要选择一个type啊

sample是这样的

Matisse.from(SampleActivity.this)
.choose(MimeType.ofAll(), false)
...

源码实际上是这样的

public SelectionSpecBuilder choose(Set<MimeType> mimeType) {
return new SelectionSpecBuilder(this, mimeType);
}

所以,你的应该是这样的

Matisse.from(MainActivity.this)
.choose(MimeType.allOf())
...

没有boolean类型参数,而且也不是​​ofAll​​​了,而是​​allOf​​。

上面是把所有的都列出来,那我如果只选图片怎么办呢

sample是这样的

Matisse.from(SampleActivity.this)
.choose(MimeType.ofImage())
...

尼玛。。实际上​​MimeType​​​这个枚举类中根本就没有​​ofImage​

所以你的应该是这样的

Matisse.from(MainActivity.this)
.choose(MimeType.of(MimeType.JPEG))
...

所以,刺不刺激?

对了,你如果要用最新版本,比如​​v0.5.0-beta3​​,注意去掉前面的v。

然后,你可以跑起来了,也不会报错了,仿佛一切都ok的样子(翻译一下:其实并没有,逃..)

遇到几个点还没有解决,也懒得深入研究了,我要回家过年,哼

  1. 拍照还是选择相册,没有处理
  2. 预览,选择图片的时候可以预览,但是回调之后并不行,没有处理
  3. onActivityResult回调之后的图片不能直接删除,没有处理
  4. 剪裁,没有处理
  5. 压缩,没有处理
  6. 哦对了,如果可以预览了,那还得可以保存图片呢,也没有处理,因为预览没有处理,哈哈哈嗝
  7. 已选择的图片,再次选择的时候带过去,没有处理

那有人就会说了,这么多没有的功能,或者文档没有介绍到的,不是可以自己去处理吗,这样岂不是定制化更高?比如筛选条件、主题…
emmm…
你说的对,但我不认同。哈哈哈

哦对了,选择图片的时候可以预览,看一下是什么样的
Android 选择图片、上传图片之Matisse_android选择图片_05

啊。。scaleType不对就不说了,可是你让我的toolbar兄弟如何自处?又要挨window爸爸的打了。。

哦对了,0.5的版本加了新功能,但是正式版还没有发布

Android 选择图片、上传图片之Matisse_android选择图片_06

最后,不要忘了加权限和FileProvider。
然后贴一下MainActivity的代码和gayhub的地址

package com.yechaoa.matissedemo;

import android.Manifest;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
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.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.tbruyelle.rxpermissions2.RxPermissions;
import com.zhihu.matisse.Matisse;
import com.zhihu.matisse.MimeType;
import com.zhihu.matisse.internal.entity.CaptureStrategy;

import java.util.List;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private UriAdapter mAdapter;
private static final int REQUEST_CODE_CHOOSE = 23;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findViewById(R.id.zhihu).setOnClickListener(this);
findViewById(R.id.dracula).setOnClickListener(this);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.setAdapter(mAdapter = new UriAdapter());
}

/**
* 1 预览 2 已选择带过去 3 剪裁 4 压缩
* <p>
* 120 显示三列 100显示四列
*/

@Override
public void onClick(final View v) {
RxPermissions rxPermissions = new RxPermissions(MainActivity.this);
rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onNext(Boolean aBoolean) {
if (aBoolean) {
switch (v.getId()) {
case R.id.zhihu:
Matisse.from(MainActivity.this)
.choose(MimeType.allOf())//ofAll()
.theme(R.style.Matisse_Zhihu)//主题,夜间模式R.style.Matisse_Dracula
.countable(true)//是否显示选中数字
.capture(true)//是否提供拍照功能
.captureStrategy(new CaptureStrategy(true, "com.zhihu.matisse.sample.fileprovider"))//存储地址
.maxSelectable(9)//最大选择数
//.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))//筛选条件
.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))//图片大小
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)//屏幕方向
.thumbnailScale(0.85f)//缩放比例
.imageEngine(new MyGlideEngine())//图片加载方式
.forResult(REQUEST_CODE_CHOOSE);//请求码
break;
case R.id.dracula:
Matisse.from(MainActivity.this)
.choose(MimeType.of(MimeType.JPEG))//ofImage()
.theme(R.style.Matisse_Dracula)
.countable(false)
.maxSelectable(9)
.imageEngine(new MyGlideEngine())
.forResult(REQUEST_CODE_CHOOSE);
break;
}
mAdapter.setData(null);
} else {
Toast.makeText(MainActivity.this, "权限被拒绝了..", Toast.LENGTH_LONG).show();
}
}

@Override
public void onError(Throwable e) {

}

@Override
public void onComplete() {

}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {
mAdapter.setData(Matisse.obtainResult(data));
}
}

private class UriAdapter extends RecyclerView.Adapter<UriAdapter.UriViewHolder> {

private List<Uri> mUris;

void setData(List<Uri> uris) {
mUris = uris;
notifyDataSetChanged();
}

@Override
public UriViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new UriViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.uri_item, parent, false));
}

@Override
public void onBindViewHolder(UriViewHolder holder, int position) {
Glide.with(MainActivity.this).load(mUris.get(position)).into(holder.mImg);
}

@Override
public int getItemCount() {
return mUris == null ? 0 : mUris.size();
}

class UriViewHolder extends RecyclerView.ViewHolder {

private ImageView mImg;

UriViewHolder(View contentView) {
super(contentView);
mImg = (ImageView) contentView.findViewById(R.id.img);
}
}
}

}

gayhub:​​https://github.com/yechaoa/MatisseDemo​