天天看點

Android 選擇圖檔、上傳圖檔之Matisse

效果圖:

Android 選擇圖檔、上傳圖檔之Matisse
Android 選擇圖檔、上傳圖檔之Matisse
Android 選擇圖檔、上傳圖檔之Matisse
Android 選擇圖檔、上傳圖檔之Matisse

就目前效果圖來看,好像也沒什麼毛病哈,其實我這個內建的過程是有點坎坷的。

而且,功能也不算是很齊全吧…主要展現在以下幾個點

  • 沒有回調之後的預覽
  • 選擇之後不能删除已選
  • 已選擇的圖檔再次選擇不能帶過去
  • 剪裁
  • 壓縮
  • 權限
  • 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

啊。。scaleType不對就不說了,可是你讓我的toolbar兄弟如何自處?又要挨window爸爸的打了。。

哦對了,0.5的版本加了新功能,但是正式版還沒有釋出
Android 選擇圖檔、上傳圖檔之Matisse

最後,不要忘了權重限和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