本文共 28036 字,大约阅读时间需要 93 分钟。
头像选取,裁切,上传等功能基本上是现在每个app必备的功能,实现起来倒是不复杂,确是要花点时间。恰好前几天把这个功能做完了,本着不重复造轮子的原则,提供一整套解决方案,希望给能用到的小伙伴。
首先放头像必须得有一个控件,我这里用的 CircleImageView
implementation 'de.hdodenhof:circleimageview:2.1.0'
然后是点击控件弹出选择框拍照或者是去图库选取,如图
其中底部的控件用的是第三方控件,具体可以访问我的github主页查看:
示例代码:
//头像控件点击事件logo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ActionSheetDialog actionSheetDialog = new ActionSheetDialog( mContext).builder().setCancelable(false) .setCanceledOnTouchOutside(true); for (int i = 0; i < fileFrom.length; i++) { actionSheetDialog.addSheetItem(fileFrom[i], ActionSheetDialog.SheetItemColor.Blue, new ActionSheetDialog.OnSheetItemClickListener() { @Override public void onClick(int which) { getFile(which); } }); } actionSheetDialog.show(); }});//处理点击事件private void getFile(int index) { switch (index) { case 1: takePic(); break; case 2: gallery(); break; } } //去图库选择 private void gallery() { PictureSelector.create(this) .openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio() .theme(themeId)// 主题样式设置 具体参考 values/styles 用法:R.style.picture.white.style .maxSelectNum(1)// 最大图片选择数量 .minSelectNum(1)// 最小选择数量 .isCamera(false)// 是否显示拍照按钮 .imageSpanCount(5)// 每行显示个数 .compress(false)// 是否压缩 true or false .maxSelectNum(1)// 最大图片选择数量 .isZoomAnim(true)// 图片列表点击 缩放效果 默认true .synOrAsy(true)//同步true或异步false 压缩 默认同步 .glideOverride(120, 120)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度 //.selectionMedia(picList)// 是否传入已选图片 .minimumCompressSize(100)// 小于100kb的图片不压缩 .forResult(Pic_OK);//结果回调onActivityResult code } //拍照 private void takePic() { //单独拍照 PictureSelector.create(this) .openCamera(PictureMimeType.ofImage()) .theme(themeId)// 主题样式设置 具体参考 values/styles .minSelectNum(1)// 最小选择数量 .compress(false) .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 .isCamera(false)// 是否显示拍照按钮 .glideOverride(120, 120)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度 //.selectionMedia(picList)// 是否传入已选图片 .imageSpanCount(5)// 每行显示个数 .maxSelectNum(1)// 最大图片选择数量 .isZoomAnim(true)// 图片列表点击 缩放效果 默认true .synOrAsy(true)//同步true或异步false 压缩 默认同步 .minimumCompressSize(100)// 小于100kb的图片不压缩 .forResult(Camea_OK); }
其中拍照和图库选择图片需要用到第三方框架:
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.1.9'
选取完成图片或者拍照完成之后,根据传入的result值回调到onActivityResult方法
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); LogUtils.e("requestCode : "+requestCode); switch (requestCode) { case Camea_OK: // 图片选择结果回调 List<LocalMedia> resultCamera = PictureSelector.obtainMultipleResult(data); if(resultCamera != null && resultCamera.size() > 0){ Intent cameraIntent = new Intent(mContext, ClipImageActivity.class); cameraIntent.putExtra("path",resultCamera.get(0).getPath()); startActivityForResult(cameraIntent,CLIP); } break; case Pic_OK: // 图片选择结果回调 List<LocalMedia> resultGallery = PictureSelector.obtainMultipleResult(data); if(resultGallery != null && resultGallery.size() > 0){ Intent picIntent = new Intent(mContext, ClipImageActivity.class); picIntent.putExtra("path",resultGallery.get(0).getPath()); startActivityForResult(picIntent,CLIP); } break; case CLIP: if(data != null){ String path = data.getStringExtra("result_path"); LogUtils.e("path : "+path); uploadHead(path); } break; } }
onActivityResult方法中主要是获取了图片的地址,然后通过path这个参数传入到裁剪页面,裁剪页面效果图:
裁剪页面主要是用了一个自定义的view,分别包含一个能缩放的ImageView,还有一个圆形遮罩,代码如下:
自定义view:ClipImageLayout
public class ClipImageLayout extends RelativeLayout { private ClipZoomImageView mZoomImageView; private CutImageBorderView mClipImageView; private int mHorizontalPadding = 20;// 框左右的边距,这里左右边距为0,为�?��屏幕宽度的正方形�? public ClipImageLayout(Context context, AttributeSet attrs) { super(context, attrs); mZoomImageView = new ClipZoomImageView(context); mClipImageView = new CutImageBorderView(context); android.view.ViewGroup.LayoutParams lp = new LayoutParams( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT); this.addView(mZoomImageView, lp); this.addView(mClipImageView, lp); // 计算padding的px mHorizontalPadding = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources() .getDisplayMetrics()); mZoomImageView.setHorizontalPadding(mHorizontalPadding); mClipImageView.setHorizontalPadding(mHorizontalPadding); } public void setImageDrawable(Drawable drawable) { mZoomImageView.setImageDrawable(drawable); } public void setImageBitmap(Bitmap bitmap) { mZoomImageView.setImageBitmap(bitmap); } /** * 对外公布设置边距的方�?单位为dp * * @param mHorizontalPadding */ public void setHorizontalPadding(int mHorizontalPadding) { this.mHorizontalPadding = mHorizontalPadding; } /** * 裁切图片 * * @return */ public Bitmap clip() { return mZoomImageView.clip(); }}
缩放的imageView:ClipZoomImageView
public class ClipZoomImageView extends AppCompatImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener { public static float SCALE_MAX = 4.0f; private static float SCALE_MID = 2.0f; /** * 初始化时的缩放比例,如果图片宽或高大于屏幕,此�?将小�? */ private float initScale = 1.0f; private boolean once = true; /** * 用于存放矩阵�?个�? */ private final float[] matrixValues = new float[9]; /** * 缩放的手势检�? */ private ScaleGestureDetector mScaleGestureDetector = null; private final Matrix mScaleMatrix = new Matrix(); /** * 用于双击�?�� */ private GestureDetector mGestureDetector; private boolean isAutoScale; private int mTouchSlop; private float mLastX; private float mLastY; private boolean isCanDrag; private int lastPointerCount; /** * 水平方向与View的边�? */ private int mHorizontalPadding; public ClipZoomImageView(Context context) { this(context, null); } public ClipZoomImageView(Context context, AttributeSet attrs) { super(context, attrs); setScaleType(ScaleType.MATRIX); mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { if (isAutoScale == true) return true; float x = e.getX(); float y = e.getY(); if (getScale() < SCALE_MID) { ClipZoomImageView.this.postDelayed( new AutoScaleRunnable(SCALE_MID, x, y), 16); isAutoScale = true; } else { ClipZoomImageView.this.postDelayed( new AutoScaleRunnable(initScale, x, y), 16); isAutoScale = true; } return true; } }); mScaleGestureDetector = new ScaleGestureDetector(context, this); this.setOnTouchListener(this); } /** * 自动缩放的任�? * */ private class AutoScaleRunnable implements Runnable { static final float BIGGER = 1.07f; static final float SMALLER = 0.93f; private float mTargetScale; private float tmpScale; /** * 缩放的中�? */ private float x; private float y; /** * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 * * @param targetScale */ public AutoScaleRunnable(float targetScale, float x, float y) { this.mTargetScale = targetScale; this.x = x; this.y = y; if (getScale() < mTargetScale) { tmpScale = BIGGER; } else { tmpScale = SMALLER; } } @Override public void run() { // 进行缩放 mScaleMatrix.postScale(tmpScale, tmpScale, x, y); checkBorder(); setImageMatrix(mScaleMatrix); final float currentScale = getScale(); // 如果值在合法范围内,继续缩放 if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) { ClipZoomImageView.this.postDelayed(this, 16); } else // 设置为目标的缩放比例 { final float deltaScale = mTargetScale / currentScale; mScaleMatrix.postScale(deltaScale, deltaScale, x, y); checkBorder(); setImageMatrix(mScaleMatrix); isAutoScale = false; } } } @Override public boolean onScale(ScaleGestureDetector detector) { float scale = getScale(); float scaleFactor = detector.getScaleFactor(); if (getDrawable() == null) return true; /** * 缩放的范围控�? */ if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { /** * �?��值最小�?判断 */ if (scaleFactor * scale < initScale) { scaleFactor = initScale / scale; } if (scaleFactor * scale > SCALE_MAX) { scaleFactor = SCALE_MAX / scale; } /** * 设置缩放比例 */ mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkBorder(); setImageMatrix(mScaleMatrix); } return true; } /** * 根据当前图片的Matrix获得图片的范�? * * @return */ private RectF getMatrixRectF() { Matrix matrix = mScaleMatrix; RectF rect = new RectF(); Drawable d = getDrawable(); if (null != d) { rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); matrix.mapRect(rect); } return rect; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { } @Override public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) return true; mScaleGestureDetector.onTouchEvent(event); float x = 0, y = 0; // 拿到触摸点的个数 final int pointerCount = event.getPointerCount(); // 得到多个触摸点的x与y均�? for (int i = 0; i < pointerCount; i++) { x += event.getX(i); y += event.getY(i); } x = x / pointerCount; y = y / pointerCount; /** * 每当触摸点发生变化时,重置mLasX , mLastY */ if (pointerCount != lastPointerCount) { isCanDrag = false; mLastX = x; mLastY = y; } lastPointerCount = pointerCount; switch (event.getAction()) { case MotionEvent.ACTION_MOVE: float dx = x - mLastX; float dy = y - mLastY; if (!isCanDrag) { isCanDrag = isCanDrag(dx, dy); } if (isCanDrag) { if (getDrawable() != null) { RectF rectF = getMatrixRectF(); // 如果宽度小于屏幕宽度,则禁止左右移动 if (rectF.width() <= getWidth() - mHorizontalPadding * 2) { dx = 0; } // 如果高度小雨屏幕高度,则禁止上下移动 if (rectF.height() <= getHeight() - getHVerticalPadding() * 2) { dy = 0; } mScaleMatrix.postTranslate(dx, dy); checkBorder(); setImageMatrix(mScaleMatrix); } } mLastX = x; mLastY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: lastPointerCount = 0; break; } return true; } /** * 获得当前的缩放比�? * * @return */ public final float getScale() { mScaleMatrix.getValues(matrixValues); return matrixValues[Matrix.MSCALE_X]; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } /** * 垂直方向与View的边�? */ // private int getHVerticalPadding(); @Override public void onGlobalLayout() { if (once) { Drawable d = getDrawable(); if (d == null) return; // 垂直方向的边�? // getHVerticalPadding() = (getHeight() - (getWidth() - 2 * // mHorizontalPadding)) / 2; int width = getWidth(); int height = getHeight(); // 拿到图片的宽和高 int drawableW = d.getIntrinsicWidth(); int drawableH = d.getIntrinsicHeight(); float scale = 1.0f; int frameSize = getWidth() - mHorizontalPadding * 2; // 大图 if (drawableW > frameSize && drawableH < frameSize) { scale = 1.0f * frameSize / drawableH; } else if (drawableH > frameSize && drawableW < frameSize) { scale = 1.0f * frameSize / drawableW; } else if (drawableW > frameSize && drawableH > frameSize) { float scaleW = frameSize * 1.0f / drawableW; float scaleH = frameSize * 1.0f / drawableH; scale = Math.max(scaleW, scaleH); } // 太小的图片放大处�? if (drawableW < frameSize && drawableH > frameSize) { scale = 1.0f * frameSize / drawableW; } else if (drawableH < frameSize && drawableW > frameSize) { scale = 1.0f * frameSize / drawableH; } else if (drawableW < frameSize && drawableH < frameSize) { float scaleW = 1.0f * frameSize / drawableW; float scaleH = 1.0f * frameSize / drawableH; scale = Math.max(scaleW, scaleH); } initScale = scale; SCALE_MID = initScale * 2; SCALE_MAX = initScale * 4; mScaleMatrix.postTranslate((width - drawableW) / 2, (height - drawableH) / 2); mScaleMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2); // 图片移动至屏幕中�? setImageMatrix(mScaleMatrix); once = false; } } /** * 剪切图片,返回剪切后的bitmap对象 * * @return */ public Bitmap clip() { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),Bitmap.Config.ARGB_8888); //将剪裁的图片压缩到500k以下,如果没需求就注释该段代码 ByteArrayOutputStream baos = new ByteArrayOutputStream(); int options = 100;//保存的图片自动压缩低于500k bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos); while (baos.toByteArray().length / 1024 > 500) { baos.reset(); options -= 10; bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos); } Canvas canvas = new Canvas(bitmap); draw(canvas); return Bitmap.createBitmap(bitmap, mHorizontalPadding, getHVerticalPadding(), getWidth() - 2 * mHorizontalPadding, getWidth() - 2 * mHorizontalPadding); } /** * 边界�?�� */ private void checkBorder() { RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int height = getHeight(); // 如果宽或高大于屏幕,则控制范�?; 这里�?.001是因为精度丢失会产生问题,但是误差一般很小,�?��我们直接加了�?��0.01 if (rect.width() + 0.01 >= width - 2 * mHorizontalPadding) { if (rect.left > mHorizontalPadding) { deltaX = -rect.left + mHorizontalPadding; } if (rect.right < width - mHorizontalPadding) { deltaX = width - mHorizontalPadding - rect.right; } } if (rect.height() + 0.01 >= height - 2 * getHVerticalPadding()) { if (rect.top > getHVerticalPadding()) { deltaY = -rect.top + getHVerticalPadding(); } if (rect.bottom < height - getHVerticalPadding()) { deltaY = height - getHVerticalPadding() - rect.bottom; } } mScaleMatrix.postTranslate(deltaX, deltaY); } /** * 是否是拖动行�? * * @param dx * @param dy * @return */ private boolean isCanDrag(float dx, float dy) { return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; } public void setHorizontalPadding(int mHorizontalPadding) { this.mHorizontalPadding = mHorizontalPadding; } private int getHVerticalPadding() { return (getHeight() - (getWidth() - 2 * mHorizontalPadding)) / 2; }}
圆形遮罩:CutImageBorderView
public class CutImageBorderView extends View { /** * 水平方向与View的边距 */ private int mHorizontalPadding; /** * 垂直方向与View的边距 */ private int mVerticalPadding; /** * 绘制的矩形的宽度 */ private int mWidth; /** * 边框的颜色,默认为白色 */ private int mBorderColor = Color.parseColor("#FFFFFF"); /** * 边框的宽度 单位dp */ private int mBorderWidth = 1; private Paint mPaint; public CutImageBorderView(Context context) { this(context, null); } public CutImageBorderView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CutImageBorderView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mBorderWidth = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources() .getDisplayMetrics()); mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 计算矩形区域的宽度 mWidth = getWidth() - 2 * mHorizontalPadding; // 计算距离屏幕垂直边界 的边距 mVerticalPadding = (getHeight() - mWidth) / 2; mPaint.setColor(Color.parseColor("#aa000000")); mPaint.setStyle(Paint.Style.FILL); // 绘制左边1 canvas.drawRect(0, 0, mHorizontalPadding, getHeight(), mPaint); // 绘制右边2 canvas.drawRect(getWidth() - mHorizontalPadding, 0, getWidth(), getHeight(), mPaint); // 绘制上边3 canvas.drawRect(mHorizontalPadding, 0, getWidth() - mHorizontalPadding, mVerticalPadding, mPaint); // 绘制下边4 canvas.drawRect(mHorizontalPadding, getHeight() - mVerticalPadding, getWidth() - mHorizontalPadding, getHeight(), mPaint); RectF rect = new RectF(mHorizontalPadding, mVerticalPadding, getWidth() - mHorizontalPadding, getHeight() - mVerticalPadding); Path mPath = new Path(); mPath.moveTo(mHorizontalPadding,mVerticalPadding); mPath.lineTo(mHorizontalPadding,getHeight()/2); mPath.arcTo(rect,180,90); mPath.lineTo(mHorizontalPadding,mVerticalPadding); canvas.drawPath(mPath,mPaint); mPath.reset(); mPath.moveTo(getWidth() - mHorizontalPadding,mVerticalPadding); mPath.lineTo(getWidth()/2,mVerticalPadding); mPath.arcTo(rect,270,90); mPath.lineTo(getWidth() - mHorizontalPadding,mVerticalPadding); canvas.drawPath(mPath,mPaint); mPath.reset(); mPath.moveTo(getWidth() - mHorizontalPadding,getHeight() - mVerticalPadding); mPath.lineTo(getWidth() - mHorizontalPadding,getHeight()/2); mPath.arcTo(rect,0,90); mPath.lineTo(getWidth() - mHorizontalPadding,getHeight() - mVerticalPadding); canvas.drawPath(mPath,mPaint); mPath.reset(); mPath.moveTo(mHorizontalPadding,getHeight() - mVerticalPadding); mPath.lineTo(getWidth()/2,getHeight()-mVerticalPadding); mPath.arcTo(rect,90,90); mPath.lineTo(mHorizontalPadding,getHeight() - mVerticalPadding); canvas.drawPath(mPath,mPaint); // 绘制外边框 mPaint.setColor(mBorderColor); mPaint.setStrokeWidth(mBorderWidth); mPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(getWidth()/2,getHeight()/2 ,getWidth()/2 - mHorizontalPadding,mPaint); } public void setHorizontalPadding(int mHorizontalPadding) { this.mHorizontalPadding = mHorizontalPadding; }}
最终在裁剪页面使用代码示例:
public class ClipImageActivity extends BaseActivity { @BindView(R.id.back) ImageView back; @BindView(R.id.title) TextView title; @BindView(R.id.right_btn) TextView right_btn; @BindView(R.id.clipImageLayout) ClipImageLayout clipImageLayout; private String path; @Override protected int getContentViewId() { return R.layout.activity_clip_image; } @Override protected void initBundleData() { path = getIntent().getStringExtra("path"); } @Override protected void initView() { title.setText("头像选取"); right_btn.setVisibility(View.VISIBLE); right_btn.setText("确定"); // 有的系统返回的图片是旋转了,有的没有旋转,所以处理 int degreee = readBitmapDegree(path); Bitmap bitmap = createBitmap(path); if (bitmap != null) { if (degreee == 0) { clipImageLayout.setImageBitmap(bitmap); } else { clipImageLayout.setImageBitmap(rotateBitmap(degreee, bitmap)); } } else { finish(); } } @Override protected void initData() { } @Override protected void initEvent() { back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); right_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String path = FileUtils.saveBitmapFile(clipImageLayout.clip(),"head"); Intent intent = new Intent(); intent.putExtra("result_path",path); setResult(1,intent); finish(); } }); } private Bitmap createBitmap(String path) { if (path == null) { return null; } BitmapFactory.Options opts = new BitmapFactory.Options(); //不在内存中读取图片的宽高 opts.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, opts); int width = opts.outWidth; opts.inSampleSize = width > 1080 ? (int)(width / 1080) : 1 ;//注意此处为了解决1080p手机拍摄图片过大所以做了一定压缩,否则bitmap会不显示 opts.inJustDecodeBounds = false;// 这里一定要将其设置回false,因为之前我们将其设置成了true opts.inPurgeable = true; opts.inInputShareable = true; opts.inDither = false; opts.inPurgeable = true; FileInputStream is = null; Bitmap bitmap = null; try { is = new FileInputStream(path); bitmap = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); is = null; } } catch (IOException e) { e.printStackTrace(); } } return bitmap; } // 读取图像的旋转度 private int readBitmapDegree(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; } // 旋转图片 private Bitmap rotateBitmap(int angle, Bitmap bitmap) { // 旋转图片 动作 Matrix matrix = new Matrix(); matrix.postRotate(angle); // 创建新的图片 Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); return resizedBitmap; }}
先通过path获取到原图,然后把原图设置到缩放imageview中,等确定好需要裁剪的返回,获取裁剪的图片,通过setresult返回。然后在前一个页面的onActivityResult进行处理,可以参考前面贴出的request code为CLIP的代码段,最终获取到裁剪的头像上传即可。
当然如果你想用矩形的裁剪框,可以将CutImageBorderView替换成下面的这个即可
public class ClipImageBorderView extends View { /** * 水平方向与View的边距 */ private int mHorizontalPadding; /** * 垂直方向与View的边距 */ private int mVerticalPadding; /** * 绘制的矩形的宽度 */ private int mWidth; /** * 边框的颜色,默认为白色 */ private int mBorderColor = Color.parseColor("#4D4D4D"); /** * 边框的宽度单位dp */ private int mBorderWidth = 1; private Paint mPaint; public ClipImageBorderView(Context context) { this(context, null); } public ClipImageBorderView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ClipImageBorderView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mBorderWidth = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources() .getDisplayMetrics()); mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 计算矩形区域的宽度 mWidth = getWidth() - 2 * mHorizontalPadding; // 计算距离屏幕垂直边界 的边距 mVerticalPadding = (getHeight() - mWidth) / 2; mPaint.setColor(Color.parseColor("#aa000000")); mPaint.setStyle(Style.FILL); // 绘制左边1 canvas.drawRect(0, 0, mHorizontalPadding, getHeight(), mPaint); // 绘制右边2 canvas.drawRect(getWidth() - mHorizontalPadding, 0, getWidth(), getHeight(), mPaint); // 绘制上边3 canvas.drawRect(mHorizontalPadding, 0, getWidth() - mHorizontalPadding, mVerticalPadding, mPaint); // 绘制下边4 canvas.drawRect(mHorizontalPadding, getHeight() - mVerticalPadding, getWidth() - mHorizontalPadding, getHeight(), mPaint); // 绘制外边�? mPaint.setColor(mBorderColor); mPaint.setStrokeWidth(mBorderWidth); mPaint.setStyle(Style.STROKE); canvas.drawRect(mHorizontalPadding, mVerticalPadding, getWidth() - mHorizontalPadding, getHeight() - mVerticalPadding, mPaint); } public void setHorizontalPadding(int mHorizontalPadding) { this.mHorizontalPadding = mHorizontalPadding; }}
好了, 到这里,一整套头像上传的处理方案就可以拿来即用了,直接copy代码即可。