转载请注明出处http://blog.youkuaiyun.com/u014163726/article/details/44994197
这么长时间没写博客感觉手都要生了啊,最近因为工作的关系来到了上海,目前还算稳定,所以抓紧时间写篇博客压压惊。
标题早已经看穿一切,这次我们来模仿一下qq上传头像的功能,先上一个未完成版的效果图,银魂第四季重开放上一张萌萌哒的图片。
这还是要用到我们自定义View的知识,首先从相册中获取图片的部分我就不详细介绍了。
/**
* 获得图片
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHOOSE_BIG_PICTURE) {
photoBitmap = null;
photoViewBitmap = null;
try {
Uri originalUri = data.getData();
int angle = getExifOrientation(getRealPathFromURI(originalUri));
if (angle != 0) { // 如果照片出现了 旋转 那么 就更改旋转度数
Matrix matrix = new Matrix();
matrix.postRotate(angle);
photoBitmap = getBitmapFromUri(photoBitmap, originalUri);
photoViewBitmap = Bitmap.createBitmap(photoBitmap, 0, 0,
photoBitmap.getWidth(), photoBitmap.getHeight(),
matrix, true);
clipView.setBitmap(photoViewBitmap);
} else {
clipView.setBitmap(getBitmapFromUri(photoBitmap,
originalUri));
}
photoBitmap.recycle();
photoViewBitmap.recycle();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
我当时用的是三星的Note3测试发现获取的图片会发生旋转十分的坑爹。。所以我们还需要根据uri拿到路径然后再判断图片是否旋转。
/**
* 根据Uri获得bitmap
*
* @param bitmap
* @param uri
* @return
*/
private Bitmap getBitmapFromUri(Bitmap bitmap, Uri uri) {
try {
bitmap = MediaStore.Images.Media.getBitmap(
this.getContentResolver(), uri);
return bitmap;
} catch (Exception e) {
Log.d("TAG", e.getLocalizedMessage());
return null;
}
}
/**
* 获得系统相册图片
*/
private void getAlbum() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");// 相片类型
startActivityForResult(intent, CHOOSE_BIG_PICTURE);
}
/**
* 旋转图片
*
* @param filepath
* @return
*/
private int getExifOrientation(String filepath) {
int degree = 0;
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
} catch (IOException ex) {
}
if (exif != null) {
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, -1);
if (orientation != -1) {
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;
}
}
}
return degree;
}
/**
* 根据Uri拿到路径
*
* @param contentUri
* @return
*/
public String getRealPathFromURI(Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentUri, proj, null,
null, null);
if (cursor.moveToFirst()) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
拿到图片之后就进入我们的自定义view环节啦。
public class ClipView extends View {
/**
* 画笔
*/
private Paint paint;
/**
* 图片
*/
private Bitmap mBitmap;
/**
* 画布
*/
private Canvas mCanvas;
/**
* 蒙版
*/
private Bitmap bitmap;
/**
* 起点坐标
*/
private int startX, startY;
/**
* 移动距离
*/
private int distanceX, distanceY;
/**
* 图片坐标
*/
private int widthX, heightY;
int x = 0, y = 0;
public ClipView(Context context) {
super(context);
init();
// TODO Auto-generated constructor stub
}
public ClipView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ClipView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
我们默认把传进来的图片缩放至600,800这样不会让图片过大也不会过小。
/**
* 缩放图片
*
* @param bgimage
* @param newWidth
* @param newHeight
* @return
*/
private Bitmap zoomImage(Bitmap bgimage, double newWidth, double newHeight) {
// 获取这个图片的宽和高
float width = bgimage.getWidth();
float height = bgimage.getHeight();
// 创建操作图片用的matrix对象
Matrix matrix = new Matrix();
// 计算宽高缩放率
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 缩放图片动作
matrix.postScale(scaleWidth, scaleHeight);
Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
(int) height, matrix, true);
return bitmap;
}
/**
* 拿到图片首先进行缩放
*
* @param bitmap
*/
public void setBitmap(Bitmap bitmap) {
this.mBitmap = zoomImage(bitmap, 600, 800);
startX = -(600 / 2);
startY = -(800 / 2);
widthX = startX;
heightY = startY;
postInvalidate();
}
做到这一步的时候我们再来看看效果
可以看到我们光有了图片还是远远不够滴,我们还需要一个圆以及一个蒙版效果,那么问题就来了,这个蒙版效果是怎么做的呢,再上一张图,图片来自网络
看到这张图我们要知道先绘制的是黄色的后绘制的是蓝色的,那么我们蒙版的效果要用哪种来实现呢。
我选择用DstOut,这种模式取得是非交集下层部分。理清了思路,接下来我们就继续写代码吧。
private void init() {
// 创建空白画布
bitmap = Bitmap.createBitmap(600, 800, Config.ARGB_8888);
mCanvas = new Canvas(bitmap);
paint = new Paint();
paint.setStyle(Style.FILL);
paint.setStrokeWidth(2);
paint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(getWidth() / 2, getHeight() / 2);
if (mBitmap != null) {
restartCanvas();
canvas.drawBitmap(mBitmap, widthX, heightY, null);
mCanvas.drawCircle(-widthX, -heightY, 200, paint);
canvas.drawBitmap(bitmap, widthX, heightY, null);
}
}
我们再onDraw中绘制了我们的背景图片以及蒙版效果再加一个半径为200的圆,接下来做的就是不断的改变背景位置来完成移动的效果,每次移动之前要先clear掉上次的画布。
private void restartCanvas() {
// 清空上一次的绘图状态
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mCanvas.drawPaint(paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mCanvas.drawColor(getResources().getColor(R.color.bg));
}
要记清楚DSTOUT的效果哦!
/**
* 移动x位置
*/
private void getWidthX() {
widthX = startX - distanceX;
if (widthX > -200) {
widthX = -200;
distanceX = -100;
} else if (widthX < -400) {
widthX = -400;
distanceX = 100;
}
}
/**
* 移动y位置
*/
private void getHeightY() {
heightY = startY - distanceY;
if (heightY > -200) {
heightY = -200;
distanceY = -100;
} else if (heightY < -600) {
heightY = -600;
distanceY = 100;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = (int) event.getX();
y = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
distanceX = x - (int) (event.getX());
distanceY = y - (int) (event.getY());
getWidthX();
getHeightY();
break;
case MotionEvent.ACTION_UP:
startX = widthX;
startY = heightY;
break;
default:
break;
}
postInvalidate();
return true;
}
今天这部分的代码就到这里了,可以看到目前我们还欠缺的是随手势放大背景图片,以及最后的剪切!这就留到下一次吧。。。