天天看點

Android 選擇圖檔、上傳圖檔之PictureSelectorDemo:https://github.com/yechaoa/PictureSelectorDemo

效果圖:

Android 選擇圖檔、上傳圖檔之PictureSelectorDemo:https://github.com/yechaoa/PictureSelectorDemo
Android 選擇圖檔、上傳圖檔之PictureSelectorDemo:https://github.com/yechaoa/PictureSelectorDemo
Android 選擇圖檔、上傳圖檔之PictureSelectorDemo:https://github.com/yechaoa/PictureSelectorDemo
Android 選擇圖檔、上傳圖檔之PictureSelectorDemo:https://github.com/yechaoa/PictureSelectorDemo

【注意】Demo已更新到最新版本,并稍作調整。(2019-07-05)

之前出過一篇 Android 選擇圖檔、上傳圖檔之ImagePicker,這個是okgo作者出的,就一般需求來講是夠了,但是沒有壓縮,需要自己去搞。

後來業務需求提升,頁面要美,體驗要好,便不是那麼滿足需求了,所幸在github上找到PictureSelector(然後當時沒多久Matisse就開源了…可以看這裡Android 選擇圖檔、上傳圖檔之Matisse),也不用自己再撸一個了,下面來介紹介紹PictureSelector

github

https://github.com/LuckSiege/PictureSelector

目前是一直在維護的,支援從相冊或拍照選擇圖檔或視訊、音頻,支援動态權限擷取、裁剪(單圖or多圖裁剪)、壓縮、主題自定義配置等功能、适配android 6.0+系統,而且你能遇到的問題,README文檔都有解決方案。

功能特點

功能齊全,且相容性好,作者也做了相容測試

1.适配android6.0+系統

2.解決部分機型裁剪閃退問題

3.解決圖檔過大oom閃退問題

4.動态擷取系統權限,避免閃退

5.支援相片or視訊的單選和多選

6.支援裁剪比例設定,如常用的 1:1、3:4、3:2、16:9 預設為圖檔大小

7.支援視訊預覽

8.支援gif圖檔

9.支援.webp格式圖檔

10.支援一些常用場景設定:如:是否裁剪、是否預覽圖檔、是否顯示相機等

11.新增自定義主題設定

12.新增圖檔勾選樣式設定

13.新增圖檔裁剪寬高設定

14.新增圖檔壓縮處理

15.新增錄視訊最大時間設定

16.新增視訊清晰度設定

17.新增QQ選擇風格,帶數字效果

18.新增自定義 文字顔色 背景色讓風格和項目更搭配

19.新增多圖裁剪功能

20.新增LuBan多圖壓縮

21.新增單獨拍照功能

22.新增壓縮大小設定

23.新增Luban壓縮檔次設定

24.新增圓形頭像裁剪

25.新增音頻功能查詢

主題配置

這個就想怎麼改就怎麼改了

<!--預設樣式 注意* 樣式隻可修改,不能删除任何一項 否則報錯-->
    <style name="picture.default.style" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <!--标題欄背景色-->
        <item name="colorPrimary">@color/bar_grey</item>
        <!--狀态欄背景色-->
        <item name="colorPrimaryDark">@color/bar_grey</item>
        <!--是否改變圖檔清單界面狀态欄字型顔色為黑色-->
        <item name="picture.statusFontColor">false</item>
        <!--傳回鍵圖示-->
        <item name="picture.leftBack.icon">@drawable/picture_back</item>
        <!--标題下拉箭頭-->
        <item name="picture.arrow_down.icon">@drawable/arrow_down</item>
        <!--标題上拉箭頭-->
        <item name="picture.arrow_up.icon">@drawable/arrow_up</item>
        <!--标題文字顔色-->
        <item name="picture.title.textColor">@color/white</item>
        <!--标題欄右邊文字-->
        <item name="picture.right.textColor">@color/white</item>
        <!--圖檔清單勾選樣式-->
        <item name="picture.checked.style">@drawable/checkbox_selector</item>
        <!--開啟圖檔清單勾選數字模式-->
        <item name="picture.style.checkNumMode">false</item>
        <!--選擇圖檔樣式0/9-->
        <item name="picture.style.numComplete">false</item>
        <!--圖檔清單底部背景色-->
        <item name="picture.bottom.bg">@color/color_fa</item>
        <!--圖檔清單預覽文字顔色-->
        <item name="picture.preview.textColor">@color/tab_color_true</item>
        <!--圖檔清單已完成文字顔色-->
        <item name="picture.complete.textColor">@color/tab_color_true</item>
        <!--圖檔已選數量圓點背景色-->
        <item name="picture.num.style">@drawable/num_oval</item>
        <!--預覽界面标題文字顔色-->
        <item name="picture.ac_preview.title.textColor">@color/white</item>
        <!--預覽界面已完成文字顔色-->
        <item name="picture.ac_preview.complete.textColor">@color/tab_color_true</item>
        <!--預覽界面标題欄背景色-->
        <item name="picture.ac_preview.title.bg">@color/bar_grey</item>
        <!--預覽界面底部背景色-->
        <item name="picture.ac_preview.bottom.bg">@color/bar_grey_90</item>
        <!--預覽界面狀态欄顔色-->
        <item name="picture.status.color">@color/bar_grey_90</item>
        <!--預覽界面傳回箭頭-->
        <item name="picture.preview.leftBack.icon">@drawable/picture_back</item>
        <!--是否改變預覽界面狀态欄字型顔色為黑色-->
        <item name="picture.preview.statusFontColor">false</item>
        <!--裁剪頁面标題背景色-->
        <item name="picture.crop.toolbar.bg">@color/bar_grey</item>
        <!--裁剪頁面狀态欄顔色-->
        <item name="picture.crop.status.color">@color/bar_grey</item>
        <!--裁剪頁面标題文字顔色-->
        <item name="picture.crop.title.color">@color/white</item>
        <!--相冊檔案夾清單選中圖示-->
        <item name="picture.folder_checked_dot">@drawable/orange_oval</item>
    </style>           

複制

功能配置

// 進入相冊 以下是例子:用不到的api可以不寫
 PictureSelector.create(MainActivity.this)
 	.openGallery()//全部.PictureMimeType.ofAll()、圖檔.ofImage()、視訊.ofVideo()、音頻.ofAudio()
 	.theme()//主題樣式(不設定為預設樣式) 也可參考demo values/styles下 例如:R.style.picture.white.style
 	.maxSelectNum()// 最大圖檔選擇數量 int
 	.minSelectNum()// 最小選擇數量 int
	.imageSpanCount(4)// 每行顯示個數 int
 	.selectionMode()// 多選 or 單選 PictureConfig.MULTIPLE or PictureConfig.SINGLE
 	.previewImage()// 是否可預覽圖檔 true or false
 	.previewVideo()// 是否可預覽視訊 true or false
	.enablePreviewAudio() // 是否可播放音頻 true or false
 	.isCamera()// 是否顯示拍照按鈕 true or false
	.imageFormat(PictureMimeType.PNG)// 拍照儲存圖檔格式字尾,預設jpeg
	.isZoomAnim(true)// 圖檔清單點選 縮放效果 預設true
	.sizeMultiplier(0.5f)// glide 加載圖檔大小 0~1之間 如設定 .glideOverride()無效
	.setOutputCameraPath("/CustomPath")// 自定義拍照儲存路徑,可不填
 	.enableCrop()// 是否裁剪 true or false
 	.compress()// 是否壓縮 true or false
 	.glideOverride()// int glide 加載寬高,越小圖檔清單越流暢,但會影響清單圖檔浏覽的清晰度
 	.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定義
 	.hideBottomControls()// 是否顯示uCrop工具欄,預設不顯示 true or false
 	.isGif()// 是否顯示gif圖檔 true or false
	.compressSavePath(getPath())//壓縮圖檔儲存位址
 	.freeStyleCropEnabled()// 裁剪框是否可拖拽 true or false
 	.circleDimmedLayer()// 是否圓形裁剪 true or false
 	.showCropFrame()// 是否顯示裁剪矩形邊框 圓形裁剪時建議設為false   true or false
 	.showCropGrid()// 是否顯示裁剪矩形網格 圓形裁剪時建議設為false    true or false
 	.openClickSound()// 是否開啟點選聲音 true or false
 	.selectionMedia()// 是否傳入已選圖檔 List<LocalMedia> list
 	.previewEggs()// 預覽圖檔時 是否增強左右滑動圖檔體驗(圖檔滑動一半即可看到上一張是否選中) true or false
 	.cropCompressQuality()// 裁剪壓縮品質 預設90 int
 	.minimumCompressSize(100)// 小于100kb的圖檔不壓縮 
 	.synOrAsy(true)//同步true或異步false 壓縮 預設同步
 	.cropWH()// 裁剪寬高比,設定如果大于圖檔本身寬高則無效 int 
 	.rotateEnabled() // 裁剪是否可旋轉圖檔 true or false
 	.scaleEnabled()// 裁剪是否可放大縮小圖檔 true or false
 	.videoQuality()// 視訊錄制品質 0 or 1 int
	.videoMaxSecond(15)// 顯示多少秒以内的視訊or音頻也可适用 int 
    .videoMinSecond(10)// 顯示多少秒以内的視訊or音頻也可适用 int 
	.recordVideoSecond()//視訊秒數錄制 預設60s int
	.isDragFrame(false)// 是否可拖動裁剪框(固定)
 	.forResult(PictureConfig.CHOOSE_REQUEST);//結果回調onActivityResult code                

複制

內建方式

compile引入

dependencies {
    implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3'
}           

複制

build.gradle加入

allprojects {
   repositories {
      jcenter()
      maven { url 'https://jitpack.io' }
   }
}           

複制

使用

使用非常簡單,你想要的基本上都有

package com.yechaoa.pictureselectordemo;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
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.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import com.luck.picture.lib.permissions.Permission;
import com.luck.picture.lib.permissions.RxPermissions;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.functions.Consumer;

public class MainActivity extends AppCompatActivity {

    private int maxSelectNum = 9;
    private List<LocalMedia> selectList = new ArrayList<>();
    private GridImageAdapter adapter;
    private RecyclerView mRecyclerView;
    private PopupWindow pop;

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

        mRecyclerView = findViewById(R.id.recycler);

        initWidget();
    }

    private void initWidget() {
        FullyGridLayoutManager manager = new FullyGridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(manager);
        adapter = new GridImageAdapter(this, onAddPicClickListener);
        adapter.setList(selectList);
        adapter.setSelectMax(maxSelectNum);
        mRecyclerView.setAdapter(adapter);
        adapter.setOnItemClickListener(new GridImageAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position, View v) {
                if (selectList.size() > 0) {
                    LocalMedia media = selectList.get(position);
                    String pictureType = media.getPictureType();
                    int mediaType = PictureMimeType.pictureToVideo(pictureType);
                    switch (mediaType) {
                        case 1:
                            // 預覽圖檔 可自定長按儲存路徑
                            //PictureSelector.create(MainActivity.this).externalPicturePreview(position, "/custom_file", selectList);
                            PictureSelector.create(MainActivity.this).externalPicturePreview(position, selectList);
                            break;
                        case 2:
                            // 預覽視訊
                            PictureSelector.create(MainActivity.this).externalPictureVideo(media.getPath());
                            break;
                        case 3:
                            // 預覽音頻
                            PictureSelector.create(MainActivity.this).externalPictureAudio(media.getPath());
                            break;
                    }
                }
            }
        });
    }

    private GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {

        @SuppressLint("CheckResult")
        @Override
        public void onAddPicClick() {
            //擷取寫的權限
            RxPermissions rxPermission = new RxPermissions(MainActivity.this);
            rxPermission.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .subscribe(new Consumer<Permission>() {
                        @Override
                        public void accept(Permission permission) {
                            if (permission.granted) {// 使用者已經同意該權限
                                //第一種方式,彈出選擇和拍照的dialog
                                showPop();

                                //第二種方式,直接進入相冊,但是 是有拍照得按鈕的
//                                showAlbum();
                            } else {
                                Toast.makeText(MainActivity.this, "拒絕", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
        }
    };

    private void showAlbum() {
        //參數很多,根據需要添加
        PictureSelector.create(MainActivity.this)
                .openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、圖檔.ofImage()、視訊.ofVideo()、音頻.ofAudio()
                .maxSelectNum(maxSelectNum)// 最大圖檔選擇數量
                .minSelectNum(1)// 最小選擇數量
                .imageSpanCount(4)// 每行顯示個數
                .selectionMode(PictureConfig.MULTIPLE)// 多選 or 單選PictureConfig.MULTIPLE : PictureConfig.SINGLE
                .previewImage(true)// 是否可預覽圖檔
                .isCamera(true)// 是否顯示拍照按鈕
                .isZoomAnim(true)// 圖檔清單點選 縮放效果 預設true
                //.setOutputCameraPath("/CustomPath")// 自定義拍照儲存路徑
                .enableCrop(true)// 是否裁剪
                .compress(true)// 是否壓縮
                //.sizeMultiplier(0.5f)// glide 加載圖檔大小 0~1之間 如設定 .glideOverride()無效
                .glideOverride(160, 160)// glide 加載寬高,越小圖檔清單越流暢,但會影響清單圖檔浏覽的清晰度
                .withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定義
                //.selectionMedia(selectList)// 是否傳入已選圖檔
                //.previewEggs(false)// 預覽圖檔時 是否增強左右滑動圖檔體驗(圖檔滑動一半即可看到上一張是否選中)
                //.cropCompressQuality(90)// 裁剪壓縮品質 預設100
                //.compressMaxKB()//壓縮最大值kb compressGrade()為Luban.CUSTOM_GEAR有效
                //.compressWH() // 壓縮寬高比 compressGrade()為Luban.CUSTOM_GEAR有效
                //.cropWH()// 裁剪寬高比,設定如果大于圖檔本身寬高則無效
                .rotateEnabled(false) // 裁剪是否可旋轉圖檔
                //.scaleEnabled()// 裁剪是否可放大縮小圖檔
                //.recordVideoSecond()//錄制視訊秒數 預設60s
                .forResult(PictureConfig.CHOOSE_REQUEST);//結果回調onActivityResult code
    }

    private void showPop() {
        View bottomView = View.inflate(MainActivity.this, R.layout.layout_bottom_dialog, null);
        TextView mAlbum = bottomView.findViewById(R.id.tv_album);
        TextView mCamera = bottomView.findViewById(R.id.tv_camera);
        TextView mCancel = bottomView.findViewById(R.id.tv_cancel);

        pop = new PopupWindow(bottomView, -1, -2);
        pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        pop.setOutsideTouchable(true);
        pop.setFocusable(true);
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.alpha = 0.5f;
        getWindow().setAttributes(lp);
        pop.setOnDismissListener(new PopupWindow.OnDismissListener() {

            @Override
            public void onDismiss() {
                WindowManager.LayoutParams lp = getWindow().getAttributes();
                lp.alpha = 1f;
                getWindow().setAttributes(lp);
            }
        });
        pop.setAnimationStyle(R.style.main_menu_photo_anim);
        pop.showAtLocation(getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);

        View.OnClickListener clickListener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (view.getId()) {
                    case R.id.tv_album:
                        //相冊
                        PictureSelector.create(MainActivity.this)
                                .openGallery(PictureMimeType.ofImage())
                                .maxSelectNum(maxSelectNum)
                                .minSelectNum(1)
                                .imageSpanCount(4)
                                .selectionMode(PictureConfig.MULTIPLE)
                                .forResult(PictureConfig.CHOOSE_REQUEST);
                        break;
                    case R.id.tv_camera:
                        //拍照
                        PictureSelector.create(MainActivity.this)
                                .openCamera(PictureMimeType.ofImage())
                                .forResult(PictureConfig.CHOOSE_REQUEST);
                        break;
                    case R.id.tv_cancel:
                        //取消
                        //closePopupWindow();
                        break;
                }
                closePopupWindow();
            }
        };

        mAlbum.setOnClickListener(clickListener);
        mCamera.setOnClickListener(clickListener);
        mCancel.setOnClickListener(clickListener);
    }

    public void closePopupWindow() {
        if (pop != null && pop.isShowing()) {
            pop.dismiss();
            pop = null;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        List<LocalMedia> images;
        if (resultCode == RESULT_OK) {
            if (requestCode == PictureConfig.CHOOSE_REQUEST) {// 圖檔選擇結果回調

                images = PictureSelector.obtainMultipleResult(data);
                selectList.addAll(images);

                //selectList = PictureSelector.obtainMultipleResult(data);

                // 例如 LocalMedia 裡面傳回三種path
                // 1.media.getPath(); 為原圖path
                // 2.media.getCutPath();為裁剪後path,需判斷media.isCut();是否為true
                // 3.media.getCompressPath();為壓縮後path,需判斷media.isCompressed();是否為true
                // 如果裁剪并壓縮了,以取壓縮路徑為準,因為是先裁剪後壓縮的
                adapter.setList(selectList);
                adapter.notifyDataSetChanged();
            }
        }
    }

}           

複制

Demo:https://github.com/yechaoa/PictureSelectorDemo