一、技术概述

Android项目中经常会使用多图上传功能,但是Android自带的选择器只能够选择一张图片。这个选择可以适用于Android项目中的多图显示功能。

二、技术详述

布局主要是简单的RecyclerView以及一个拖动到此处删除的框

        

定义Adaptor工具类——GridImageAdapter

public class GridImageAdapter extends        RecyclerView.Adapter {    public static final String TAG = "PictureSelector";    public static final int TYPE_CAMERA = 1;    public static final int TYPE_PICTURE = 2;    private LayoutInflater mInflater;    private List list = new ArrayList<>();    private int selectMax = 9;    /**     * 点击添加图片跳转     */    private onAddPicClickListener mOnAddPicClickListener;    public interface onAddPicClickListener {        void onAddPicClick();    }    /**     * 删除     */    public void delete(int position) {        try {            if (position != RecyclerView.NO_POSITION && list.size() > position) {                list.remove(position);                notifyItemRemoved(position);                notifyItemRangeChanged(position, list.size());            }        } catch (Exception e) {            e.printStackTrace();        }    }    public GridImageAdapter(Context context, onAddPicClickListener mOnAddPicClickListener) {        this.mInflater = LayoutInflater.from(context);        this.mOnAddPicClickListener = mOnAddPicClickListener;    }    public void setSelectMax(int selectMax) {        this.selectMax = selectMax;    }    public void setList(List list) {        this.list = list;    }    public List getData() {        return list == null ? new ArrayList<>() : list;    }    public void remove(int position) {        if (list != null && position < list.size()) {            list.remove(position);        }    }    public class ViewHolder extends RecyclerView.ViewHolder {        ImageView mImg;        ImageView mIvDel;        TextView tvDuration;        public ViewHolder(View view) {            super(view);            mImg = view.findViewById(R.id.fiv);            mIvDel = view.findViewById(R.id.iv_del);            tvDuration = view.findViewById(R.id.tv_duration);        }    }    @Override    public int getItemCount() {        if (list.size() < selectMax) {            return list.size() + 1;        } else {            return list.size();        }    }    @Override    public int getItemViewType(int position) {        if (isShowAddItem(position)) {            return TYPE_CAMERA;        } else {            return TYPE_PICTURE;        }    }    /**     * 创建ViewHolder     */    @Override    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {        View view = mInflater.inflate(R.layout.gv_filter_image,                viewGroup, false);        final ViewHolder viewHolder = new ViewHolder(view);        return viewHolder;    }    private boolean isShowAddItem(int position) {        int size = list.size() == 0 ? 0 : list.size();        return position == size;    }    /**     * 设置值     */    @Override    public void onBindViewHolder(final ViewHolder viewHolder, final int position) {        //少于8张,显示继续添加的图标        if (getItemViewType(position) == TYPE_CAMERA) {            viewHolder.mImg.setImageResource(R.drawable.ic_add_image);            viewHolder.mImg.setOnClickListener(v -> mOnAddPicClickListener.onAddPicClick());            viewHolder.mIvDel.setVisibility(View.INVISIBLE);        } else {            viewHolder.mIvDel.setVisibility(View.VISIBLE);            viewHolder.mIvDel.setOnClickListener(view -> {                int index = viewHolder.getAdapterPosition();                // 这里有时会返回-1造成数据下标越界,具体可参考getAdapterPosition()源码,                // 通过源码分析应该是bindViewHolder()暂未绘制完成导致,知道原因的也可联系我~感谢                if (index != RecyclerView.NO_POSITION && list.size() > index) {                    list.remove(index);                    notifyItemRemoved(index);                    notifyItemRangeChanged(index, list.size());                }            });            LocalMedia media = list.get(position);            if (media == null                    || TextUtils.isEmpty(media.getPath())) {                return;            }            int chooseModel = media.getChooseModel();            String path;            if (media.isCut() && !media.isCompressed()) {                // 裁剪过                path = media.getCutPath();            } else if (media.isCompressed() || (media.isCut() && media.isCompressed())) {                // 压缩过,或者裁剪同时压缩过,以最终压缩过图片为准                path = media.getCompressPath();            } else {                // 原图                path = media.getPath();            }            Log.i(TAG, "原图地址::" + media.getPath());            if (media.isCut()) {                Log.i(TAG, "裁剪地址::" + media.getCutPath());            }            if (media.isCompressed()) {                Log.i(TAG, "压缩地址::" + media.getCompressPath());                Log.i(TAG, "压缩后文件大小::" + new File(media.getCompressPath()).length() / 1024 + "k");            }            if (!TextUtils.isEmpty(media.getAndroidQToPath())) {                Log.i(TAG, "Android Q特有地址::" + media.getAndroidQToPath());            }            if (media.isOriginal()) {                Log.i(TAG, "是否开启原图功能::" + true);                Log.i(TAG, "开启原图功能后地址::" + media.getOriginalPath());            }            long duration = media.getDuration();            viewHolder.tvDuration.setVisibility(PictureMimeType.isHasVideo(media.getMimeType())                    ? View.VISIBLE : View.GONE);            if (chooseModel == PictureMimeType.ofAudio()) {                viewHolder.tvDuration.setVisibility(View.VISIBLE);                viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds                        (R.drawable.picture_icon_audio, 0, 0, 0);            } else {                viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds                        (R.drawable.picture_icon_video, 0, 0, 0);            }            viewHolder.tvDuration.setText(DateUtils.formatDurationTime(duration));            if (chooseModel == PictureMimeType.ofAudio()) {                viewHolder.mImg.setImageResource(R.drawable.picture_audio_placeholder);            } else {                Glide.with(viewHolder.itemView.getContext())                        .load(PictureMimeType.isContent(path) && !media.isCut() && !media.isCompressed() ? Uri.parse(path)                                : path)                        .centerCrop()                        .placeholder(R.color.app_color_f6)                        .diskCacheStrategy(DiskCacheStrategy.ALL)                        .into(viewHolder.mImg);            }            //itemView 的点击事件            if (mItemClickListener != null) {                viewHolder.itemView.setOnClickListener(v -> {                    int adapterPosition = viewHolder.getAdapterPosition();                    mItemClickListener.onItemClick(v, adapterPosition);                });            }            if (mItemLongClickListener != null) {                viewHolder.itemView.setOnLongClickListener(v -> {                    int adapterPosition = viewHolder.getAdapterPosition();                    mItemLongClickListener.onItemLongClick(viewHolder, adapterPosition, v);                    return true;                });            }        }    }    private OnItemClickListener mItemClickListener;    public void setOnItemClickListener(OnItemClickListener l) {        this.mItemClickListener = l;    }    private OnItemLongClickListener mItemLongClickListener;    public void setItemLongClickListener(OnItemLongClickListener l) {        this.mItemLongClickListener = l;    }}

定义获取图片缓存工具类——ImageCacheUtils

public class ImageCacheUtils {    /**     * 根据url获取图片缓存     * Glide 4.x请调用此方法     * 注意:此方法必须在子线程中进行     *     * @param context     * @param url     * @return     */    public static File getCacheFileTo4x(Context context, String url) {        try {            return Glide.with(context).downloadOnly().load(url).submit().get();        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    /**     * 根据url获取图片缓存     * Glide 3.x请调用此方法     * 注意:此方法必须在子线程中进行     *     * @param context     * @param url     * @return     */    public static File getCacheFileTo3x(Context context, String url) {        try {            return Glide.with(context).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get();        } catch (Exception e) {            e.printStackTrace();            return null;        }    }}

定义Glide引擎工具类——GlideEngine

public class GlideEngine implements ImageEngine {    /**     * 加载图片     *     * @param context     * @param url     * @param imageView     */    @Override    public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {        Glide.with(context)                .load(url)                .into(imageView);    }    /**     * 加载网络图片适配长图方案     * # 注意:此方法只有加载网络图片才会回调     *     * @param context     * @param url     * @param imageView     * @param longImageView     * @param callback      网络图片加载回调监听 {link after version 2.5.1 Please use the #OnImageCompleteCallback#}     */    @Override    public void loadImage(@NonNull Context context, @NonNull String url,                          @NonNull final ImageView imageView,                          final SubsamplingScaleImageView longImageView, final OnImageCompleteCallback callback) {        Glide.with(context)                .asBitmap()                .load(url)                .into(new ImageViewTarget(imageView) {                    @Override                    public void onLoadStarted(@Nullable Drawable placeholder) {                        super.onLoadStarted(placeholder);                        if (callback != null) {                            callback.onShowLoading();                        }                    }                    @Override                    public void onLoadFailed(@Nullable Drawable errorDrawable) {                        super.onLoadFailed(errorDrawable);                        if (callback != null) {                            callback.onHideLoading();                        }                    }                    @Override                    protected void setResource(@Nullable Bitmap resource) {                        if (callback != null) {                            callback.onHideLoading();                        }                        if (resource != null) {                            boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),                                    resource.getHeight());                            longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);                            imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);                            if (eqLongImage) {                                // 加载长图                                longImageView.setQuickScaleEnabled(true);                                longImageView.setZoomEnabled(true);                                longImageView.setPanEnabled(true);                                longImageView.setDoubleTapZoomDuration(100);                                longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);                                longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);                                longImageView.setImage(ImageSource.bitmap(resource),                                        new ImageViewState(0, new PointF(0, 0), 0));                            } else {                                // 普通图片                                imageView.setImageBitmap(resource);                            }                        }                    }                });    }    /**     * 加载网络图片适配长图方案     * # 注意:此方法只有加载网络图片才会回调     *     * @param context     * @param url     * @param imageView     * @param longImageView     * @ 已废弃     */    @Override    public void loadImage(@NonNull Context context, @NonNull String url,                          @NonNull final ImageView imageView,                          final SubsamplingScaleImageView longImageView) {        Glide.with(context)                .asBitmap()                .load(url)                .into(new ImageViewTarget(imageView) {                    @Override                    protected void setResource(@Nullable Bitmap resource) {                        if (resource != null) {                            boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),                                    resource.getHeight());                            longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);                            imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);                            if (eqLongImage) {                                // 加载长图                                longImageView.setQuickScaleEnabled(true);                                longImageView.setZoomEnabled(true);                                longImageView.setPanEnabled(true);                                longImageView.setDoubleTapZoomDuration(100);                                longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);                                longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);                                longImageView.setImage(ImageSource.bitmap(resource),                                        new ImageViewState(0, new PointF(0, 0), 0));                            } else {                                // 普通图片                                imageView.setImageBitmap(resource);                            }                        }                    }                });    }    /**     * 加载相册目录     *     * @param context   上下文     * @param url       图片路径     * @param imageView 承载图片ImageView     */    @Override    public void loadFolderImage(@NonNull final Context context, @NonNull String url, @NonNull final ImageView imageView) {        Glide.with(context)                .asBitmap()                .load(url)                .override(180, 180)                .centerCrop()                .sizeMultiplier(0.5f)                .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))                .into(new BitmapImageViewTarget(imageView) {                    @Override                    protected void setResource(Bitmap resource) {                        RoundedBitmapDrawable circularBitmapDrawable =                                RoundedBitmapDrawableFactory.                                        create(context.getResources(), resource);                        circularBitmapDrawable.setCornerRadius(8);                        imageView.setImageDrawable(circularBitmapDrawable);                    }                });    }    /**     * 加载gif     *     * @param context   上下文     * @param url       图片路径     * @param imageView 承载图片ImageView     */    @Override    public void loadAsGifImage(@NonNull Context context, @NonNull String url,                               @NonNull ImageView imageView) {        Glide.with(context)                .asGif()                .load(url)                .into(imageView);    }    /**     * 加载图片列表图片     *     * @param context   上下文     * @param url       图片路径     * @param imageView 承载图片ImageView     */    @Override    public void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {        Glide.with(context)                .load(url)                .override(200, 200)                .centerCrop()                .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))                .into(imageView);    }    private GlideEngine() {    }    private static GlideEngine instance;    public static GlideEngine createGlideEngine() {        if (null == instance) {            synchronized (GlideEngine.class) {                if (null == instance) {                    instance = new GlideEngine();                }            }        }        return instance;    }}

最后一个工具类FullyGridLayoutManager

public class FullyGridLayoutManager extends GridLayoutManager {    public FullyGridLayoutManager(Context context, int spanCount) {        super(context, spanCount);    }    public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {        super(context, spanCount, orientation, reverseLayout);    }    private int[] mMeasuredDimension = new int[2];    @Override    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {        final int widthMode = View.MeasureSpec.getMode(widthSpec);        final int heightMode = View.MeasureSpec.getMode(heightSpec);        final int widthSize = View.MeasureSpec.getSize(widthSpec);        final int heightSize = View.MeasureSpec.getSize(heightSpec);        int width = 0;        int height = 0;        int count = getItemCount();        int span = getSpanCount();        for (int i = 0; i < count; i++) {            measureScrapChild(recycler, i,                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),                    mMeasuredDimension);            if (getOrientation() == HORIZONTAL) {                if (i % span == 0) {                    width = width + mMeasuredDimension[0];                }                if (i == 0) {                    height = mMeasuredDimension[1];                }            } else {                if (i % span == 0) {                    height = height + mMeasuredDimension[1];                }                if (i == 0) {                    width = mMeasuredDimension[0];                }            }        }        switch (widthMode) {            case View.MeasureSpec.EXACTLY:                width = widthSize;            case View.MeasureSpec.AT_MOST:            case View.MeasureSpec.UNSPECIFIED:        }        switch (heightMode) {            case View.MeasureSpec.EXACTLY:                height = heightSize;            case View.MeasureSpec.AT_MOST:            case View.MeasureSpec.UNSPECIFIED:        }        setMeasuredDimension(width, height);    }    final RecyclerView.State mState = new RecyclerView.State();    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,                                   int heightSpec, int[] measuredDimension) {        int itemCount = mState.getItemCount();        if (position < itemCount) {            try {                View view = recycler.getViewForPosition(0);                if (view != null) {                    RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();                    int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,                            getPaddingLeft() + getPaddingRight(), p.width);                    int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,                            getPaddingTop() + getPaddingBottom(), p.height);                    view.measure(childWidthSpec, childHeightSpec);                    measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;                    measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;                    recycler.recycleView(view);                }            } catch (Exception e) {                e.printStackTrace();            }        }    }}

做好以上工具类的创建后,就可以开始搭建图片选择器了
首先初始化RecylerView以及GridImageAdapter

    mRecyclerView = findViewById(R.id.publish_article_recycler);    FullyGridLayoutManager manager = new FullyGridLayoutManager(this,            4, GridLayoutManager.VERTICAL, false);    mRecyclerView.setLayoutManager(manager);    mRecyclerView.addItemDecoration(new GridSpacingItemDecoration(4,            ScreenUtils.dip2px(this, 8), false));    mAdapter = new GridImageAdapter(getContext(), onAddPicClickListener);    mAdapter.setSelectMax(maxSelectNum);

给adaptor添加点击事件

mAdapter.setOnItemClickListener((v, position) -> {    List selectList = mAdapter.getData();    if (selectList.size() > 0) {        LocalMedia media = selectList.get(position);        String mimeType = media.getMimeType();        int mediaType = PictureMimeType.getMimeType(mimeType);        switch (mediaType) {            case PictureConfig.TYPE_VIDEO:                // 预览视频                PictureSelector.create(PublishArticle.this)                        .themeStyle(R.style.picture_default_style)                        .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题                        .externalPictureVideo(TextUtils.isEmpty(media.getAndroidQToPath()) ? media.getPath() : media.getAndroidQToPath());                break;            default:                // 预览图片 可自定长按保存路径//                        PictureWindowAnimationStyle animationStyle = new PictureWindowAnimationStyle();//                        animationStyle.activityPreviewEnterAnimation = R.anim.picture_anim_up_in;//                        animationStyle.activityPreviewExitAnimation = R.anim.picture_anim_down_out;                PictureSelector.create(PublishArticle.this)                        .themeStyle(R.style.picture_default_style) // xml设置主题                        .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题                        //.setPictureWindowAnimationStyle(animationStyle)// 自定义页面启动动画                        .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)// 设置相册Activity方向,不设置默认使用系统                        .isNotPreviewDownload(true)// 预览图片长按是否可以下载                        //.bindCustomPlayVideoCallback(new MyVideoSelectedPlayCallback(getContext()))// 自定义播放回调控制,用户可以使用自己的视频播放界面                        .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项                        .openExternalPreview(position, selectList);                break;        }    }});mAdapter.setItemLongClickListener((holder, position, v) -> {    //如果item不是最后一个,则执行拖拽    needScaleBig = true;    needScaleSmall = true;    int size = mAdapter.getData().size();    if (size != maxSelectNum) {        mItemTouchHelper.startDrag(holder);        return;    }    if (holder.getLayoutPosition() != size - 1) {        mItemTouchHelper.startDrag(holder);    }});mRecyclerView.setAdapter(mAdapter);mDragListener = new DragListener() {    @Override    public void deleteState(boolean isDelete) {        if (isDelete) {            tvDeleteText.setText(getString(R.string.app_let_go_drag_delete));            tvDeleteText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.ic_let_go_delete, 0, 0);        } else {            tvDeleteText.setText(getString(R.string.app_drag_delete));            tvDeleteText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.picture_icon_delete, 0, 0);        }    }    @Override    public void dragState(boolean isStart) {        int visibility = tvDeleteText.getVisibility();        if (isStart) {            if (visibility == View.GONE) {                tvDeleteText.animate().alpha(1).setDuration(300).setInterpolator(new AccelerateInterpolator());                tvDeleteText.setVisibility(View.VISIBLE);            }        } else {            if (visibility == View.VISIBLE) {                tvDeleteText.animate().alpha(0).setDuration(300).setInterpolator(new AccelerateInterpolator());                tvDeleteText.setVisibility(View.GONE);            }        }    }};

触摸事件的编写

mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {    @Override    public boolean isLongPressDragEnabled() {        return true;    }    @Override    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {    }    @Override    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {        int itemViewType = viewHolder.getItemViewType();        if (itemViewType != GridImageAdapter.TYPE_CAMERA) {            viewHolder.itemView.setAlpha(0.7f);        }        return makeMovementFlags(ItemTouchHelper.DOWN | ItemTouchHelper.UP                | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0);    }    @Override    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {        //得到item原来的position        try {            int fromPosition = viewHolder.getAdapterPosition();            //得到目标position            int toPosition = target.getAdapterPosition();            int itemViewType = target.getItemViewType();            if (itemViewType != GridImageAdapter.TYPE_CAMERA) {                if (fromPosition < toPosition) {                    for (int i = fromPosition; i < toPosition; i++) {                        Collections.swap(mAdapter.getData(), i, i + 1);                    }                } else {                    for (int i = fromPosition; i > toPosition; i--) {                        Collections.swap(mAdapter.getData(), i, i - 1);                    }                }                mAdapter.notifyItemMoved(fromPosition, toPosition);            }        } catch (Exception e) {            e.printStackTrace();        }        return true;    }    @Override    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,                            @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {        int itemViewType = viewHolder.getItemViewType();        if (itemViewType != GridImageAdapter.TYPE_CAMERA) {            if (null == mDragListener) {                return;            }            if (needScaleBig) {                //如果需要执行放大动画                viewHolder.itemView.animate().scaleXBy(0.1f).scaleYBy(0.1f).setDuration(100);                //执行完成放大动画,标记改掉                needScaleBig = false;                //默认不需要执行缩小动画,当执行完成放大 并且松手后才允许执行                needScaleSmall = false;            }            int sh = recyclerView.getHeight() + tvDeleteText.getHeight();            int ry = tvDeleteText.getBottom() - sh;            if (dY >= ry) {                //拖到删除处                mDragListener.deleteState(true);                if (isUpward) {                    //在删除处放手,则删除item                    viewHolder.itemView.setVisibility(View.INVISIBLE);                    mAdapter.delete(viewHolder.getAdapterPosition());                    resetState();                    return;                }            } else {//没有到删除处                if (View.INVISIBLE == viewHolder.itemView.getVisibility()) {                    //如果viewHolder不可见,则表示用户放手,重置删除区域状态                    mDragListener.dragState(false);                }                if (needScaleSmall) {//需要松手后才能执行                    viewHolder.itemView.animate().scaleXBy(1f).scaleYBy(1f).setDuration(100);                }                mDragListener.deleteState(false);            }            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);        }    }    @Override    public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {        int itemViewType = viewHolder != null ? viewHolder.getItemViewType() : GridImageAdapter.TYPE_CAMERA;        if (itemViewType != GridImageAdapter.TYPE_CAMERA) {            if (ItemTouchHelper.ACTION_STATE_DRAG == actionState && mDragListener != null) {                mDragListener.dragState(true);            }            super.onSelectedChanged(viewHolder, actionState);        }    }    @Override    public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {        needScaleSmall = true;        isUpward = true;        return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);    }    @Override    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {        int itemViewType = viewHolder.getItemViewType();        if (itemViewType != GridImageAdapter.TYPE_CAMERA) {            viewHolder.itemView.setAlpha(1.0f);            super.clearView(recyclerView, viewHolder);            mAdapter.notifyDataSetChanged();            resetState();        }    }});

不要忘记绑定

// 绑定拖拽事件mItemTouchHelper.attachToRecyclerView(mRecyclerView);// 注册广播BroadcastManager.getInstance(getContext()).registerReceiver(broadcastReceiver,        BroadcastAction.ACTION_DELETE_PREVIEW_POSITION);

最后集成LuckSiege的PictureSelector2.0

private GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {        @Override        public void onAddPicClick() {                // 进入相册 以下是例子:不需要的api可以不写                PictureSelector.create(PublishArticle.this)                        .openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()                        .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项                        .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题                        .setPictureCropStyle(mCropParameterStyle)// 动态自定义裁剪主题                        .maxSelectNum(maxSelectNum)// 最大图片选择数量                        .minSelectNum(1)// 最小选择数量//                        .isOriginalImageControl(true)                        .isCompress(true)// 是否压缩                        .compressQuality(20)// 图片压缩后输出质量 0~ 100                        .isEnableCrop(true)// 是否裁剪                        .freeStyleCropEnabled(true)// 裁剪框是否可拖拽//                        .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false                        .hideBottomControls(true)// 是否显示uCrop工具栏,默认不显示                        .selectionData(mAdapter.getData())// 是否传入已选图片                        .imageSpanCount(4)// 每行显示个数                        .isReturnEmpty(false)// 未选择数据时点击按钮是否可以返回                        .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)// 设置相册Activity方向,不设置默认使用系统                        .forResult(new MyResultCallback(mAdapter));        }    };    /**     * 返回结果回调     */    private static class MyResultCallback implements OnResultCallbackListener {        private WeakReference mAdapterWeakReference;        public MyResultCallback(GridImageAdapter adapter) {            super();            this.mAdapterWeakReference = new WeakReference<>(adapter);        }        @Override        public void onResult(List result) {            for (LocalMedia media : result) {                Log.i(TAG, "是否压缩:" + media.isCompressed());                Log.i(TAG, "压缩:" + media.getCompressPath());                Log.i(TAG, "原图:" + media.getPath());                Log.i(TAG, "是否裁剪:" + media.isCut());                Log.i(TAG, "裁剪:" + media.getCutPath());                Log.i(TAG, "是否开启原图:" + media.isOriginal());                Log.i(TAG, "原图路径:" + media.getOriginalPath());                Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath());                Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight());                Log.i(TAG, "Size: " + media.getSize());                //可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息            }            if (mAdapterWeakReference.get() != null) {                mAdapterWeakReference.get().setList(result);                mAdapterWeakReference.get().notifyDataSetChanged();            }        }        @Override        public void onCancel() {            Log.i(TAG, "PictureSelector Cancel");        }    }

再根据自己的需要进行一些回调接口的编写,就能大致实现一个可以多选图片并显示的activity了

三、问题与解决

  • 在和后端的交互过程中,因为图片大小限制的原因,我们需要对图片进行一定程度的压缩。万幸的是PictureSelector自带裁剪和压缩的功能,只需要在创建时明确自己的参数,就可以实现相关的功能了。

  • 拖拉功能的实现是难度比较大的。我根据的是LuckSiege的Github中所给出的demo进行修改所完成的功能,大家如果需要可以利用LuckSiege的demo进行尝试和修改。

  • 对于LocalMedia类型的说明,这是LuckSiege中定义的一个文件类型,可以选择音频、视频、图片等,在这个项目中,我只使用了图片的文件类型,具体的大家可以到LuckSiege的GitHub上去查看相关说明。

四、总结

集成PictureSelector2.0并不难,难的是如何对Selector所选择的图片进行相关的操作,如排序、删除、再次添加等等,大多数新手都会面对这样的问题,我集成了Selector但是我并不知道如何去保存这些数据,如何向后端传输这些数据,这些问题,都可以通过下载demo,对demo进行分析然后再根据需要,对demo进行集成,不仅解决了主要问题,还可以学习到别人的代码。

五、参考博客

LuckSiege的PictureSelector2.0

Glide的使用详解

更多相关文章

  1. Android下Button实现图文混排效果
  2. eclipse 中设置android emulator 选项
  3. android 动态加载布局文件三种方法
  4. android将老项目改为按屏幕大小自适应,只需2步
  5. android ImageButton响应不规则图片
  6. android 问题汇总系列之八
  7. android ScrollView,ListView 截屏并保存到图库
  8. Android(安卓)使用OKHttp获取字符串和下载图片
  9. Android之Android(安卓)studio设置背景图片

随机推荐

  1. Android 开发小经验
  2. recommend a book for android newcomer
  3. Android 系统监听,监听USB的插拔
  4. android认识
  5. Kotlin初体验(一)-引入Android(安卓)Studio
  6. Android RatingBar案例
  7. Android 开发环境
  8. Android 歌词Lrc显示 自定义View
  9. Android NDK R8 发布
  10. android美女电子相册