Android 选择图片、上传图片之Matisse

简介: Android 选择图片、上传图片之Matisse

效果图:

image.pngimage.png


就目前效果图来看,好像也没什么毛病哈,其实我这个集成的过程是有点坎坷的。

而且,功能也不算是很齐全吧…主要体现在以下几个点


没有回调之后的预览

选择之后不能删除已选

已选择的图片再次选择不能带过去

剪裁

压缩

权限

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的样子(翻译一下:其实并没有,逃..)


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


拍照还是选择相册,没有处理

预览,选择图片的时候可以预览,但是回调之后并不行,没有处理

onActivityResult回调之后的图片不能直接删除,没有处理

剪裁,没有处理

压缩,没有处理

哦对了,如果可以预览了,那还得可以保存图片呢,也没有处理,因为预览没有处理,哈哈哈嗝

已选择的图片,再次选择的时候带过去,没有处理

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

emmm…

你说的对,但我不认同。哈哈哈


哦对了,选择图片的时候可以预览,看一下是什么样的

image.png


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


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




最后,不要忘了加权限和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

目录
相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
87 0
|
4月前
|
XML Java Android开发
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
648 0
|
14天前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
37 20
Android经典面试题之图片Bitmap怎么做优化
|
4月前
|
Android开发
Android通过手势(多点)缩放和拖拽图片
Android通过手势(多点)缩放和拖拽图片
43 4
|
4月前
|
Java Android开发
android 下载图片的问题
android 下载图片的问题
38 3
|
1月前
|
数据处理 开发工具 数据安全/隐私保护
Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路
本文探讨了Android平台上推流模块中添加文字与PNG水印的技术演进。自2015年起,为了满足应急指挥及安防领域的需求,逐步发展出三代水印技术:第一代为静态文字与图像水印;第二代实现了动态更新水印内容的能力,例如实时位置与时间信息;至第三代,则优化了数据传输效率,直接使用Bitmap对象传递水印数据至JNI层,减少了内存拷贝次数。这些迭代不仅提升了用户体验和技术效率,也体现了开发者追求极致与不断创新的精神。
|
1月前
|
自然语言处理 定位技术 API
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
本文介绍如何在Android中从图片提取地理位置信息并转换为地址。首先利用`ExifInterface`获取图片内的经纬度,然后通过`Geocoder`将经纬度转为地址。注意操作需在子线程进行且考虑多语言支持。
130 4
|
1月前
|
XML 前端开发 Android开发
Android经典实战之Kotlin中实现圆角图片和圆形图片
本文介绍两种实现圆角图像视图的方法。第一种是通过自定义Kotlin `AppCompatImageView`,重写`onDraw`方法使用`Canvas`和`Path`进行圆角剪裁。第二种利用Android Material库中的`ShapeableImageView`,简单配置即可实现圆角效果。两种方法均易于实现且提供动态调整圆角半径的功能。
34 0
|
3月前
|
JSON 编解码 Apache
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
45 1
|
3月前
|
Java Android开发
18. 【Android教程】图片控件 ImageView
18. 【Android教程】图片控件 ImageView
56 4