【Android实战】图片选取、拍摄、裁剪、上传

图片上传

效果图展示

Drawing Drawing

图片上传前的准备

带圆角的方形图片

使用的第三方控件,主要关注如下一些文件

  • RoundedDrawable
  • RoundedImageView
  • RoundedTransformationBuilder
  • res目录下的anim、color以及values下的attrs

布局文件代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.soulrelay.uploadpic"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" 
    android:background="@color/f5f5f5">

    <com.soulrelay.uploadpic.view.RoundedImageView
        android:id="@+id/imageCover"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginLeft="50dp"
        android:layout_centerVertical="true"
        android:scaleType="center"
        android:src="@drawable/default_cover_img"
        app:border_color="@color/border"
        app:border_width="1dip"
        app:corner_radius="10dp"
        app:mutate_background="true"
        app:oval="false" />

    <TextView
        android:id="@+id/add_cover_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_toRightOf="@id/imageCover"
        android:text="添加封面"
        android:textColor="@color/_3e363d"
        android:textSize="15sp" />

</RelativeLayout>

从下而上弹出的PopupWindow

关注如下文件:

  • CoverSelelctPopupWindow
  • cover_select_pop_layout.xml
public class CoverSelelctPopupWindow extends PopupWindow {

    private Button albumBtn, photoGraphBtn,cancelBtn;

    private View mMenuView;

    public CoverSelelctPopupWindow(Activity context, OnClickListener itemsOnClick) {
        super(context);
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mMenuView = inflater.inflate(R.layout.cover_select_pop_layout, null);
        albumBtn = (Button) mMenuView.findViewById(R.id.btn_album);
        photoGraphBtn = (Button) mMenuView.findViewById(R.id.btn_photo_graph);
        //startRecordBtn = (Button) mMenuView.findViewById(R.id.btn_upload_record);
        cancelBtn = (Button) mMenuView.findViewById(R.id.btn_cancel_join);
        // 设置按钮监听
        albumBtn.setOnClickListener(itemsOnClick);
        photoGraphBtn.setOnClickListener(itemsOnClick);

        // 设置SelectPicPopupWindow的View
        this.setContentView(mMenuView);
        // 设置SelectPicPopupWindow弹出窗体的宽
        this.setWidth(LayoutParams.FILL_PARENT);
        // 设置SelectPicPopupWindow弹出窗体的高
        this.setHeight(LayoutParams.WRAP_CONTENT);
        // 设置SelectPicPopupWindow弹出窗体可点击
        this.setFocusable(true);
        // 设置SelectPicPopupWindow弹出窗体动画效果
        this.setAnimationStyle(R.style.AnimBottom);
        // 实例化一个ColorDrawable颜色为半透明
        ColorDrawable dw = new ColorDrawable(0x00FFFFFF);
        // 设置SelectPicPopupWindow弹出窗体的背景
        this.setBackgroundDrawable(dw);
        // mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框
        mMenuView.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {

                int height = mMenuView.findViewById(R.id.pop_layout).getTop();
                int y = (int) event.getY();
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (y < height) {
                        dismiss();
                    }
                }
                return true;
            }
        });

        cancelBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
    }

}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/pop_layout"
        android:layout_width="fill_parent"
        android:layout_height="175dp"
        android:background="@color/f33e363d"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <Button
            android:id="@+id/btn_album"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dip"
            android:layout_marginRight="20dip"
            android:layout_marginTop="16dip"
            android:textSize="14sp"
            android:background="@drawable/btn_report_selector"
            android:text="@string/user_info_photo_album"
            android:textColor="@color/_3e363d" />

        <Button
            android:id="@+id/btn_photo_graph"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dip"
            android:layout_marginRight="20dip"
            android:layout_marginTop="8dip"
            android:textSize="14sp"
            android:background="@drawable/btn_report_selector"
            android:text="@string/user_info_photo_camera"
            android:textColor="@color/_3e363d" />

        <Button
            android:id="@+id/btn_cancel_join"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dip"
            android:layout_marginLeft="20dip"
            android:layout_marginRight="20dip"
            android:textSize="14sp"
            android:background="@drawable/btn_report_selector"
            android:text="@string/join_cancel_txt"
            android:textColor="@color/_6f6a6f" />
    </LinearLayout>

</RelativeLayout>

通过拍照以及相册获取图片

public class MainActivity extends Activity implements android.view.View.OnClickListener {

    private RoundedImageView imgCover;

    private TextView addCover;

    private CoverSelelctPopupWindow coverSelelctPopupWindow;

    public static final int ACTIVITY_ALBUM_REQUESTCODE = 2000;

    public static final int ACTIVITY_CAMERA_REQUESTCODE = 2001;

    public static final int ACTIVITY_MODIFY_PHOTO_REQUESTCODE = 2002;

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

    private void initViews() {
        imgCover = (RoundedImageView) this.findViewById(R.id.imageCover);
        addCover = (TextView) this.findViewById(R.id.add_cover_txt);
        imgCover.setOnClickListener(this);
        addCover.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.imageCover:
            case R.id.add_cover_txt:
                coverSelelctPopupWindow = new CoverSelelctPopupWindow(this, itemsOnClick);
                coverSelelctPopupWindow.showAtLocation(findViewById(R.id.add_cover_txt), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置
                break;
            default:
                break;
        }

    }

    // 为弹出窗口实现监听类
    private OnClickListener itemsOnClick = new OnClickListener() {
        public void onClick(View v) {
            coverSelelctPopupWindow.dismiss();
            if (CommonUtils.isFastDoubleClick()) {
                return;
            }
            switch (v.getId()) {
                case R.id.btn_album:
                    Intent i = new Intent(Intent.ACTION_PICK, null);// 调用android的图库
                    i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                    startActivityForResult(i, ACTIVITY_ALBUM_REQUESTCODE);
                    break;

                case R.id.btn_photo_graph:
                    if (CommonUtils.isExistCamera(MainActivity.this)) {
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 调用android自带的照相机
                        Uri imageUri = Uri.fromFile(FileUtil.getHeadPhotoFileRaw());
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                        intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
                        startActivityForResult(intent, ACTIVITY_CAMERA_REQUESTCODE);
                    } else {
                        Toast.makeText(MainActivity.this,
                                getResources().getString(R.string.user_no_camera),
                                Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case ACTIVITY_ALBUM_REQUESTCODE:
                if (resultCode == Activity.RESULT_OK) {
                    if(data.getData() == null){
                        ToastUtils.toast(this, getString(R.string.pic_not_valid));
                        return;
                    }
                    CommonUtils.cutPhoto(this, data.getData(), true);
                }
                break;
            case ACTIVITY_CAMERA_REQUESTCODE:
                if (resultCode == Activity.RESULT_OK) {
                    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
                    bitmapOptions.inSampleSize = 2;
                    int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
                    Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
                    cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
                    FileUtil.saveCutBitmapForCache(this,cameraBitmap);
                    CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
                }
                break;
            case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
//                Bundle bundle = data.getExtras();
//                if (bundle != null) {
//                    Bitmap bitmap = bundle.getParcelable("data");
//                    if (bitmap == null) {
//                        return;
//                    }
//                    headImg.setImageBitmap(bitmap);
//                }
                String coverPath = FileUtil.getHeadPhotoDir()  + FileUtil.HEADPHOTO_NAME_TEMP;
                Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
                imgCover.setImageBitmap(bitmap);
                //接下来是完成上传功能
               /* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid="
                        + LoginUtils.getInstance(this), coverPath, this);*/
                //成功之后删除临时图片
                FileUtil.deleteTempAndRaw();

                break;

        }
    }
}

拍照获取图片失败的问题

过程中发现,如果拍照获取图片的存储路径与裁切后存储的路径一致的话会出现问题,所以分别设置了两个路径,请参考

  • FileUtil
    相关代码
public class FileUtil {
    private static final String TAG = "FileUtil";
    // 用户头像保存位置
    private final static String HEADPHOTO_PATH = "/Android/data/com.soulrelay.uploadpic/";

    // 剪切头像时临时保存头像名字,完成或取消时删除
    public final static String HEADPHOTO_NAME_TEMP = "user_photo_temp.jpg";
    //拍照临时存取图片
    public final static String HEADPHOTO_NAME_RAW = "user_photo_raw.jpg";

    // 剪切壁纸图片
    private final static String WALLPAPER = "wallpaper.jpg";


    public static String getCropPath(String path) {
        String storageState = Environment.getExternalStorageState();
        if (Environment.MEDIA_REMOVED.equals(storageState)) {
            return null;
        }

        String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH + "cache" + File.separator;

        String s = MD5.Md5Encode(path)+".jpg";
        return dirPath + s;
    }

    /**
     * 用户头像保存路径
     */
    public static String getHeadPhotoDir() {
        String storageState = Environment.getExternalStorageState();
        if (Environment.MEDIA_REMOVED.equals(storageState)) {
            return null;
        }
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH;
        SDCardUtil.mkdirs(path);
        return path;
    }

    /**
     * 剪切头像时临时保存头像名字,完成或取消时删除
     */
    public static File getHeadPhotoFileTemp() {
        File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_TEMP);
        return file;
    }

    /**
     * 剪切头像时临时保存头像名字,完成或取消时删除(用于拍照时存储原始图片)
     */
    public static File getHeadPhotoFileRaw() {
        File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_RAW);
        return file;
    }

    /**
     * 获取剪切壁纸图片
     */
    public static File getWallPaperFile() {
        File file = new File(getHeadPhotoDir() + WALLPAPER);
        return file;
    }

    public static void saveCutBitmapForCache(Context context, Bitmap bitmap) {
        File file = new File(getHeadPhotoDir() + /*File.separator +*/ HEADPHOTO_NAME_RAW);
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 读取图片属性:旋转的角度
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    public static int readPictureDegree(String path) {
        int degree  = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转图片
     * @param angle
     * @param bitmap
     * @return Bitmap
     */
    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();;
        matrix.postRotate(angle);
        System.out.println("angle2=" + angle);
        // 创建新的图片
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizedBitmap;
    }

    /**
     * Delete the file/dir from the local disk
     * 
     */
    public static boolean deleteFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }

        File file = new File(filePath);
        if (!file.exists()) {
            Log.w(TAG, "the file is not exist while delete the file");
            return false;
        }

        return deleteDir(file);
    }

    /**
     * Delete the file from the local disk
     * 
     * @param dir
     */
    private static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            if (children != null) {
                // 递归删除目录中的子目录下
                for (int i = 0; i < children.length; i++) {
                    boolean success = deleteDir(new File(dir, children[i]));
                    if (!success) {
                        return false;
                    }
                }
            }

        }
        if (!dir.canRead() || !dir.canWrite()) {
            Log.w(TAG, "has no permission to can or write while delete the file");
            return false;
        }
        // 目录此时为空,可以删除
        return dir.delete();
    }

    /**
     * 删除临时文件(拍照的原始图片以及临时文件)
     * @param path
     */
    public static void deleteTempAndRaw() {
       deleteFile(FileUtil.getHeadPhotoDir()  + FileUtil.HEADPHOTO_NAME_TEMP);
       deleteFile(FileUtil.getHeadPhotoDir()  + FileUtil.HEADPHOTO_NAME_RAW);
    }

}

拍照获取图片角度不正确的问题

   case ACTIVITY_CAMERA_REQUESTCODE:
                if (resultCode == Activity.RESULT_OK) {
                    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
                    bitmapOptions.inSampleSize = 2;
                    int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
                    Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
                    cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
                    FileUtil.saveCutBitmapForCache(this,cameraBitmap);
                    CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
                }
                break;

如果不存在图片角度的问题可以直接调用(我测试的时候发现:型号相同,系统版本相同的手机上也有可能存在角度不统一的问题,如果有更好的处理方法,欢迎指教!)

CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);

上传成功之后删除临时文件

可以根据服务器接口形式,来进行图片上传,我这边上传的格式是
传入两个参数

  • uid 用户id
  • image 图片二进制数据
 case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
                String coverPath = FileUtil.getHeadPhotoDir()  + FileUtil.HEADPHOTO_NAME_TEMP;
                Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
                imgCover.setImageBitmap(bitmap);
                //接下来是完成上传功能
               /* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid="
                        + LoginUtils.getInstance(this), coverPath, this);*/
                //成功之后删除临时图片
                FileUtil.deleteTempAndRaw();

图片上传以及上传之后的处理

大家可以在自己的网络请求中按照如下方式处理,然后根据上传成功和失败的回调做相应的事情

ublic static void uploadCover(final Context context, final String url, final String path,
                                   final UploadLiveCoverListener listener) {
        ThreadPoolUtils.execute(new Runnable() {
            @Override
            public void run() {
                // 添加密钥
                try {
                    HttpClient client = new DefaultHttpClient();
                    MultipartEntity multipartContent = getEntity(context,
                            new HashMap<String, String>());
                    FileBody fileBody = new FileBody(new File(path), "image/jpeg", "UTF-8");
                    multipartContent.addPart("image", fileBody);
                    String ret = doPost(context, url, multipartContent, client);
                    JSONObject json = new JSONObject(ret);
                    int status = json.getInt("status");
                    if (status == 0) {
                        JSONObject resultO = json.getJSONObject("result");
                        String imgUrl = resultO.getString("img_url");
                        listener.onUploadSuccess(imgUrl);
                    }else {
                        listener.onUploadFail(status);
                    }
                    deleteTempAndRaw(path);
                } catch (Exception e) {
                    listener.onUploadFail(-1);
                }
            }
        });

    }

代码下载

源代码地址:选我选我选我

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值