个人资料上传头像模块,拍照+图库+图片剪裁+圆形头像

先看效果图:

注意: 因为模拟器的原因裁剪图片的页面只能拖拽,实际在手机上是可以放大旋转等操作的

实现思路:

1.三个自定义的view,分别是圆形的Imageview,可拖拽放大旋转的Imageview,裁剪图片的view(裁剪页面的矩形)

2.点击主界面的上传头像,开启一个透明的透明的Activity,在这个Activity中可以选择拍照或者是图库,不管选择哪种,将返回结果的图片路径传递到裁剪页面

3.裁剪页面:先将图片根据屏幕的比例等比例缩小加载成bitmap对象,设置给可拖拽放大旋转的Imageview,这个时候我们就可以对图片进行拖动放大等,最后我们将图片传递到MainActivity设置为头像,并上传至服务器

具体步骤:

1.先在MainActivity中,我们需要做三件事:点击后开启透明的选择获取图片方式的页面,注册广播接受者来接受最终处理好的图片,上传图片

                @Override
		public void onReceive(Context context, Intent intent) {
			if ("account_active".equals(intent.getAction())) {
				byte[] bis = intent.getByteArrayExtra("bitmap");
				Bitmap bitmap = BitmapFactory.decodeByteArray(bis, 0,
						bis.length);// 将图片数组转换成图片
				iv_head_img.setImageBitmap(bitmap);//这个Imageview是圆形的Imageview

				// 在这里上传图片 上传的格式看你们公司的要求了
				// 如果要转换成数组上传就使用BitmapFactory将bitmap对象转换成数组再传
				// if(bitmap != null){
				// uploadImage(bitmap, BaseApplication.userBean.getUsername());
				// }else{
				// CustomToast.createToast().showFaild(AccountUpdateActivity.this,
				// "图片文件错误");
				// }
			}
		} 
注意:上传图片我们这边是将图片转换成base64位,进行上传的,注意用post请求

2.选择图片页面,我们需要做的是:选择图片的方式拍照或者是图库,获取到的图片进行判断,将图片的位置传递给裁剪页面

       第1种    选择拍照:

               // 执行拍照前,应该先判断SD卡是否存在
		String SDState = Environment.getExternalStorageState();
		if (SDState.equals(Environment.MEDIA_MOUNTED)) {// 如果内存卡已经挂载
			Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
			intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(
					Environment.getExternalStorageDirectory(), "camera.jpg")));
			intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
			startActivityForResult(intent, SELECT_PIC_BY_TAKE_PHOTO);
		} else {
			Toast.makeText(this, "内存卡不存在", Toast.LENGTH_SHORT).show();
		} 
             返回结果后将图片路径传递给剪裁界面:

                                try {
					Intent intent = new Intent(this, ClipPictureActivity.class);// 开启裁剪的界面
					intent.putExtra("picPath", "/sdcard/camera.jpg");
					intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
							| Intent.FLAG_ACTIVITY_CLEAR_TOP);
					startActivity(intent);
					finish();
				} catch (Exception e) {
					e.printStackTrace();
				} 
        第2种     从图库获取图片路径

               // 选择照片的时候也一样,我们用Action为Intent.ACTION_GET_CONTENT,
		// 有些人使用其他的Action但我发现在有些机子中会出问题,所以优先选择这个
		Intent intent = new Intent();
		intent.setType("image/*");
		intent.setAction(Intent.ACTION_GET_CONTENT);
		startActivityForResult(intent, SELECT_PIC_BY_PICK_PHOTO);

           返回结果时,进行非空格式的判断等,并将图片路径传递给剪裁界面:
               	if (requestCode == SELECT_PIC_BY_PICK_PHOTO) {// 从相册取图片,有些手机有异常情况,请注意
			if (data == null) {
				Toast.makeText(this, "选择图片文件出错", Toast.LENGTH_LONG).show();
				return;
			}
			photoUri = data.getData();
			if (photoUri == null) {
				Toast.makeText(this, "选择图片文件出错", Toast.LENGTH_LONG).show();
				return;
			}
		}

		String[] pojo = { MediaStore.Images.Media.DATA };
		@SuppressWarnings("deprecation")
		Cursor cursor = managedQuery(photoUri, pojo, null, null, null);
		if (cursor != null) {
			int columnIndex = cursor.getColumnIndexOrThrow(pojo[0]);
			cursor.moveToFirst();
			picPath = cursor.getString(columnIndex);
			cursor.close();
		}
		if (picPath != null
				&& (picPath.endsWith(".png") || picPath.endsWith(".PNG")
						|| picPath.endsWith(".jpg") || picPath.endsWith(".JPG"))) {
			Intent intent = new Intent(this, ClipPictureActivity.class);
			intent.putExtra("picPath", picPath);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
					| Intent.FLAG_ACTIVITY_CLEAR_TOP);
			startActivity(intent);
			finish();
		} else {
			Toast.makeText(this, "选择图片文件不正确", Toast.LENGTH_SHORT).show();
		}
3.裁剪界面:为TouchImageview添加触摸事件的监听和添加全局view树的观察者,将裁剪的view添加进去,在触摸事件中对图片操作,保存图片并发广播通知MainActivity

   第一步     添加全局view树的观察者,将裁剪的view添加进去.可是为什么不直接将裁剪的view放在布局文件中?因为这个裁剪的view的大小是不确定的,我们需要根据图片的大小来设置剪裁view的大小!

    那为什么不在直接在onCreate中添加,而要在TouchImageview的全局view树的观察者中添加呢?因为在系统再调用onCreate方法时,并没有把布局文件中的每个view画出来,

                只是知道布局中有这么个东西,不信你可以试试,在onCreate方法中获取任何一个空间的宽和高试试,会是0.而我们在viewTree的观察者中的onGlobalLayout是在控件已经

                 全部画上去之后才调用,这个时候我们自然也会能获得每个空间的真实大小,而不是0

     

             ViewTreeObserver observer = srcPic.getViewTreeObserver();
		observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
			@SuppressWarnings("deprecation")
			public void onGlobalLayout() {
				srcPic.getViewTreeObserver().removeGlobalOnLayoutListener(this);
				initClipView(srcPic.getTop());//添加裁剪的view
			}
		});

第二步  添加裁剪的view,并将图片按屏幕的比例显示出来           
        /**
	 * 初始化截图区域,并将源图按裁剪框比例缩放
	 * 
	 * @param top
	 */
	private void initClipView(int top) {
		bitmap = getBitmapByPath(url);//将原图压缩到原来的1/2
		clipview = new ClipView(ClipPictureActivity.this);
		clipview.setCustomTopBarHeight(top);
		clipview.addOnDrawCompleteListener(new OnDrawListenerComplete() {
			public void onDrawCompelete() {
				clipview.removeOnDrawCompleteListener();
				int clipHeight = clipview.getClipHeight();
				int clipWidth = clipview.getClipWidth();
				int midX = clipview.getClipLeftMargin() + (clipWidth / 2);
				int midY = clipview.getClipTopMargin() + (clipHeight / 2);

				int imageWidth = bitmap.getWidth();
				int imageHeight = bitmap.getHeight();
				// 按裁剪框求缩放比例
				float scale = (clipWidth * 1.0f) / imageWidth;
				if (imageWidth > imageHeight) {
					scale = (clipHeight * 1.0f) / imageHeight;
				}

				// 起始中心点
				float imageMidX = imageWidth * scale / 2;
				float imageMidY = clipview.getCustomTopBarHeight()
						+ imageHeight * scale / 2;
				srcPic.setScaleType(ScaleType.MATRIX);

				// 缩放
				matrix.postScale(scale, scale);
				// 平移
				matrix.postTranslate(midX - imageMidX, midY - imageMidY);

				srcPic.setImageMatrix(matrix);
				srcPic.setImageBitmap(bitmap);
			}
		});

		this.addContentView(clipview, new LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
	} 
第三步  触摸事件 

     第一个手指按下默认是拖拽   第二个手机按下根据两个手指间的距离  如果大于10个像素  就认为是缩放  根据手机移动的距离将图片移动和缩放

    手指离开屏幕清除模式

  

        public boolean onTouch(View v, MotionEvent event) {
		ImageView view = (ImageView) v;
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			savedMatrix.set(matrix);
			// 设置开始点位置
			start.set(event.getX(), event.getY());
			mode = DRAG;
			break;
		case MotionEvent.ACTION_POINTER_DOWN://第二个手指按下
			oldDist = spacing(event);
			if (oldDist > 10f) {//缩放
				savedMatrix.set(matrix);
				midPoint(mid, event);
				mode = ZOOM;
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			mode = NONE;
			break;
		case MotionEvent.ACTION_MOVE:
			if (mode == DRAG) {
				matrix.set(savedMatrix);
				matrix.postTranslate(event.getX() - start.x, event.getY()
						- start.y);
			} else if (mode == ZOOM) {
				float newDist = spacing(event);
				if (newDist > 10f) {
					matrix.set(savedMatrix);
					float scale = newDist / oldDist;
					matrix.postScale(scale, scale, mid.x, mid.y);//根据mid进行缩放
				}
			}
			break;
		}
		view.setImageMatrix(matrix);
		return true;
	}

	/**
	 * 多点触控时,计算最先放下的两指距离
	 * 
	 * @param event
	 * @return
	 */
	private float spacing(MotionEvent event) {
		float x = event.getX(0) - event.getX(1);
		float y = event.getY(0) - event.getY(1);
		return (float) Math.sqrt(x * x + y * y);
	}

	/**
	 * 多点触控时,计算最先放下的两指中心坐标
	 * 
	 * @param point
	 * @param event
	 */
	private void midPoint(PointF point, MotionEvent event) {
		float x = event.getX(0) + event.getX(1);
		float y = event.getY(0) + event.getY(1);
		point.set(x / 2, y / 2);
	}
 
第四步  保存图片并将图片传递到MainActivity中
     
 	private void save() {
		Bitmap clipBitmap = getBitmap();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		clipBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//将图片转换成数组
		byte[] bitmapByte = baos.toByteArray();
		Intent intent = new Intent("account_active");//发广播   将图片的数组传过去
		intent.putExtra("bitmap", bitmapByte);
		sendBroadcast(intent);
		finish();
	}
        /**
     * 获取裁剪框内截图
     * 
     * @return
     */
    private Bitmap getBitmap() {
        // 获取截屏
        View view = this.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        // 获取状态栏高度
        Rect frame = new Rect();
        this.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        Bitmap finalBitmap = Bitmap.createBitmap(view.getDrawingCache(),
                clipview.getClipLeftMargin(), clipview.getClipTopMargin()
                        + statusBarHeight, clipview.getClipWidth(),
                clipview.getClipHeight());
        // 释放资源
        view.destroyDrawingCache();
        return finalBitmap;
    } 
 

最后,点击这里获取源码









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值