Android调用系统相机、本地相册上传图片(头像上传(裁剪)、多张图片上传)

开发中基本上都会有头像上传的功能,有的app还需要多张图片同时上传,下面简单将头像上传以及多张图片上传功能整理一下。图片选择仿照微信选择图片的界面。【参考】 多图片选择器
!!!推荐一个动态权限请求的框架: 动态权限申请
下面先看一下想要实现的效果图:多张图片

22222.png

选择图片:
33333.png

头像上传:
11111.png

一、头像上传(单张图片上传,可设置图片裁剪的比例)

1、选择图片前请求读写权限。

//先请求权限,再进行操作
                AndPermission.with(MainActivity.this)
                        .requestCode(300)
                        .permission(
                                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.READ_EXTERNAL_STORAGE)
                        .callback(this)
                        .start();

权限申请注解

// 成功回调的方法,用注解即可,这里的300就是请求时的requestCode。
    @PermissionYes(300)
    private void getPermissionYes(List<String> grantedPermissions) {
        // TODO 申请权限成功。
        if(AndPermission.hasPermission(this,grantedPermissions)) {
            // TODO 执行拥有权限时的下一步。
            chooseImage();
        } else {
            // 使用AndPermission提供的默认设置dialog,用户点击确定后会打开App的设置页面让用户授权。
            AndPermission.defaultSettingDialog(this, 300).show();
            // 建议:自定义这个Dialog,提示具体需要开启什么权限,自定义Dialog具体实现上面有示例代码。
        }
    }

    @PermissionNo(300)
    private void getPermissionNo(List<String> deniedPermissions) {
        // TODO 申请权限失败。
        if(AndPermission.hasPermission(this,deniedPermissions)) {
            // TODO 执行拥有权限时的下一步。
        } else {
            // 使用AndPermission提供的默认设置dialog,用户点击确定后会打开App的设置页面让用户授权。
            AndPermission.defaultSettingDialog(this, 300).show();
            // 建议:自定义这个Dialog,提示具体需要开启什么权限,自定义Dialog具体实现上面有示例代码。
        }
    }

2、初始化图片选择器,设置裁剪形状为正方形。

private ImagePicker getImagePickerSquare() {//正方形
        ImagePicker imagePicker = ImagePicker.getInstance();
        imagePicker.setImageLoader(new GlideImageLoader());   //设置图片加载器
        imagePicker.setShowCamera(true);                      //显示拍照按钮
        imagePicker.setCrop(true);                            //允许裁剪(单选才有效)
        imagePicker.setSaveRectangle(true);                   //是否按矩形区域保存
        imagePicker.setMultiMode(false);                      //多选
        imagePicker.setStyle(CropImageView.Style.RECTANGLE);  //裁剪框的形状
        imagePicker.setFocusWidth(800);                       //裁剪框的宽度。单位像素(圆形自动取宽高最小值)
        imagePicker.setFocusHeight(800);                      //裁剪框的高度。单位像素(圆形自动取宽高最小值)
        imagePicker.setOutPutX(1000);                         //保存文件的宽度。单位像素
        imagePicker.setOutPutY(1000);                         //保存文件的高度。单位像素
        return imagePicker;
    }

3、选择图片。chooseImage()

private void chooseImage() {
        List<String> names = new ArrayList<>();
        names.add("拍照");
        names.add("从相册选择");
        showDialog(new PictureChooseDialog.SelectDialogListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                switch (position) {
                    case 0: // 直接调起相机
                        //打开选择,本次允许选择的数量
                        getImagePickerSquare().setSelectLimit(maxImgCount - selImageList.size());
                        Intent intent = new Intent(MainActivity.this, ImageGridActivity.class);
                        intent.putExtra(ImageGridActivity.EXTRAS_TAKE_PICKERS,true); // 是否是直接打开相机
                        startActivityForResult(intent, REQUEST_CODE_SELECT);
                        break;
                    case 1:
                        //打开选择,本次允许选择的数量
                        getImagePickerSquare().setSelectLimit(maxImgCount - selImageList.size());
                        Intent intent1 = new Intent(MainActivity.this, ImageGridActivity.class);
                        startActivityForResult(intent1, REQUEST_CODE_SELECT);
                        break;
                    default:
                        break;
                }
            }
        }, names);
    }

4、选择图片后的处理,onActivityResult()

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {
            //添加图片返回
            if (data != null && requestCode == REQUEST_CODE_SELECT) {
                ArrayList<ImageItem> images = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);
                if (images != null){
                    ImageItem imageItem = images.get(0);
                    String newPathHead = imageItem.path;
                    updateMineMessage(newPathHead);
                }
            }
        } else if (resultCode == ImagePicker.RESULT_CODE_BACK) {
            //预览图片返回
            if (data != null && requestCode == REQUEST_CODE_PREVIEW) {
                ArrayList<ImageItem> images = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS);
                if (images != null){
                    ImageItem imageItem = images.get(0);
//                    String newPathHead = BitmapUtils.compressImageUpload(imageItem.path);
                    String newPathHead = imageItem.path;
                    updateMineMessage(newPathHead);
                }
            }
        }
    }

二、多张图片上传,选择后可删除,这里以最多九张图片为例。步骤与选择一张图片时基本一致,图片选择器稍微不同。

1、布局中图片用RecyclerView

<android.support.v7.widget.RecyclerView
            android:padding="5dp"
            android:id="@+id/recyclerView"
            android:layout_marginTop="12dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:choiceMode="singleChoice"
            android:divider="@null"
            android:fadingEdge="none"
            android:listSelector="@android:color/transparent"
            android:scrollbarStyle="outsideOverlay"
            app:layoutManager="android.support.v7.widget.GridLayoutManager"
            app:spanCount="4"
            tools:listitem="@layout/item_upload_image">
        </android.support.v7.widget.RecyclerView>

2、初始化图片选择器。

private void initImagePickerMulti() {
        ImagePicker imagePicker = ImagePicker.getInstance();
        imagePicker.setImageLoader(new GlideImageLoader());   //设置图片加载器
        imagePicker.setShowCamera(true);                      //显示拍照按钮
        imagePicker.setCrop(false);                            //允许裁剪(单选才有效)
        imagePicker.setSaveRectangle(true);                   //是否按矩形区域保存
        imagePicker.setSelectLimit(maxImgCount);              //选中数量限制
        imagePicker.setMultiMode(true);                      //多选
//        imagePicker.setStyle(CropImageView.Style.RECTANGLE);  //裁剪框的形状
//        imagePicker.setFocusWidth(800);                       //裁剪框的宽度。单位像素(圆形自动取宽高最小值)
//        imagePicker.setFocusHeight(800);                      //裁剪框的高度。单位像素(圆形自动取宽高最小值)
//        imagePicker.setOutPutX(1000);                         //保存文件的宽度。单位像素
//        imagePicker.setOutPutY(1000);                         //保存文件的高度。单位像素
    }

3、图片适配器。

public class ImagePickerAdapter extends RecyclerView.Adapter<ImagePickerAdapter.SelectedPicViewHolder> {
    private int maxImgCount;
    private Context mContext;
    private List<ImageItem> mData;
    private LayoutInflater mInflater;
    private OnRecyclerViewItemClickListener listener;
    private boolean isAdded;   //是否额外添加了最后一个图片
    private OnItemRemoveClick onItemRemoveClick;

    public boolean isAdded() {
        return isAdded;
    }

    public void setAdded(boolean added) {
        isAdded = added;
    }

    public void setOnItemRemoveClick(OnItemRemoveClick onItemRemoveClick) {
        this.onItemRemoveClick = onItemRemoveClick;
    }

    public interface OnRecyclerViewItemClickListener {
        void onItemClick(View view, int position);
    }

    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {
        this.listener = listener;
    }

    public void setImages(List<ImageItem> data) {
        mData = new ArrayList<>(data);
        if (getItemCount() < maxImgCount) {
            mData.add(new ImageItem());
            isAdded = true;
        } else {
            isAdded = false;
        }
        notifyDataSetChanged();
    }
    public void addImg() {
        if (getItemCount() < maxImgCount) {
            mData.add(new ImageItem());
            isAdded = true;
        } else {
            isAdded = false;
        }
    }

    public List<ImageItem> getImages() {
        //由于图片未选满时,最后一张显示添加图片,因此这个方法返回真正的已选图片
        if (isAdded) return new ArrayList<>(mData.subList(0, mData.size() - 1));
        else return mData;
    }

    public ImagePickerAdapter(Context mContext, List<ImageItem> data, int maxImgCount) {
        this.mContext = mContext;
        this.maxImgCount = maxImgCount;
        this.mInflater = LayoutInflater.from(mContext);
        setImages(data);
    }

    @Override
    public SelectedPicViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new SelectedPicViewHolder(mInflater.inflate(R.layout.item_upload_image, parent, false));
    }

    @Override
    public void onBindViewHolder(SelectedPicViewHolder holder, int position) {
        holder.bind(position);
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    public class SelectedPicViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private RelativeLayout cancelImg;
        private int clickPosition;
        private ImageView iv_img;

        public SelectedPicViewHolder(View itemView) {
            super(itemView);
            iv_img = (ImageView) itemView.findViewById(R.id.iv_img);
            cancelImg = ((RelativeLayout) itemView.findViewById(R.id.item_upload_image_cancelImg));
        }

        public void bind(final int position) {
            //设置条目的点击事件
            itemView.setOnClickListener(this);
            //根据条目位置设置图片
            ImageItem item = mData.get(position);
            if (isAdded && position == getItemCount() - 1) {
                iv_img.setScaleType(ImageView.ScaleType.FIT_XY);
                cancelImg.setVisibility(View.INVISIBLE);
                iv_img.setImageResource(R.mipmap.img_add);
                clickPosition = UploadMoreImagesActivity.IMAGE_ITEM_ADD;
            } else {
                iv_img.setScaleType(ImageView.ScaleType.CENTER_CROP);
                cancelImg.setVisibility(View.VISIBLE);
                ImagePicker.getInstance().getImageLoader().displayImage((Activity) mContext, item.path, iv_img, 0, 0);
                clickPosition = position;
            }
            cancelImg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    removeItem(position);
                    onItemRemoveClick.onItemRemoveClick();
                }
            });
        }

        @Override
        public void onClick(View v) {
            if (listener != null) listener.onItemClick(v, clickPosition);
        }
    }

    /**
     * 删除某条item
     * @param position
     */
    public void removeItem(int position){
        mData.remove(position);
//        notifyItemRemoved(position);
    }

    public interface OnItemRemoveClick {
        public void onItemRemoveClick();
    }

}

4、适配器中选择图片的点击事件。adapter.setOnItemClickListener(this);

@Override
    public void onItemClick(View view, int position) {
        switch (position){
            case IMAGE_ITEM_ADD:
                //先请求权限,再进行操作
                AndPermission.with(this)
                        .requestCode(300)
                        .permission(
                                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.READ_EXTERNAL_STORAGE)
                        .callback(this)
                        .start();

                break;
            default:
                //打开预览
                Intent intentPreview = new Intent(this, ImagePreviewDelActivity.class);
                intentPreview.putExtra(ImagePicker.EXTRA_IMAGE_ITEMS, (ArrayList<ImageItem>) adapter.getImages());
                intentPreview.putExtra(ImagePicker.EXTRA_SELECTED_IMAGE_POSITION, position);
                intentPreview.putExtra(ImagePicker.EXTRA_FROM_ITEMS,true);
                startActivityForResult(intentPreview, REQUEST_CODE_PREVIEW);
                break;
        }
    }

5、适配器中图片删除。

adapter.setOnItemRemoveClick(new ImagePickerAdapter.OnItemRemoveClick() {
            @Override
            public void onItemRemoveClick() {
                adapter.setImages(adapter.getImages());
                adapter.notifyDataSetChanged();
                selImageList.clear();
                selImageList.addAll(adapter.getImages());
            }
        });

6、发布时需要将图片上传至服务器,这里以 严振杰的NoHttp为例。(没有实际测试)

 /**
     * 上传图片到服务器
     */
    private void upLoadImages() {
        StringRequest request = new StringRequest("rul", RequestMethod.POST);
        request.addHeader("", "");
        request.add("content",contentEt.getText().toString());
        for (int i = 0; i < selImageList.size(); i++) {
            ImageItem imageItem = selImageList.get(i);
            String newPath = imageItem.path;
            File oldFile = new File(newPath);
            File newFile = CompressHelper.getDefault(getApplicationContext()).compressToFile(oldFile);
            request.add("imgs"+(i+1),newFile);
        }
        requestData(request, new SimpleResponseListener<String>() {
            @Override
            public void onStart(int what) {
                super.onStart(what);
            }

            @Override
            public void onSucceed(int what, Response<String> response) {
                super.onSucceed(what, response);
                //上传成功
            }
        });
    }

详细参考:

Android调用系统相机、本地相册上传图片(头像上传(裁剪)、多张图片上传)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容