Android项目中遇到的坑之(Android圆角圆形图 二)
来源:互联网 发布:2017淘宝剁手排名 编辑:程序博客网 时间:2024/05/31 19:30
接着上一篇的问题来研究研究:
**问题来了:效果是有了,但有发现么?我设置的scaleType只有fitxy
是有效果的,其他的都没有效果了。设置为其他的scaleType都变成matrix那种效果了,也就是图片默认从控件的左上角开始摆放。**
我们先看看ImageView的scaleType
以下内容来自http://www.2cto.com/kf/201411/348601.html
让我们看看scaleType的各类效果图:
ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY
android:scaleType=”center”
保持原图的大小,显示在ImageView的中心。当原图的size大于ImageView的size,超过部分裁剪处理。
android:scaleType=”centerCrop”
以填满整个ImageView为目的,将原图的中心对准ImageView的中心,等比例放大原图,直到填满ImageView为止(指的是ImageView的宽和高都要填满),原图超过ImageView的部分作裁剪处理。
android:scaleType=”centerInside”
以原图完全显示为目的,将图片的内容完整居中显示,通过按比例缩小原图的size宽(高)等于或小于ImageView的宽(高)。如果原图的size本身就小于ImageView的size,则原图的size不作任何处理,居中显示在ImageView。
android:scaleType=”matrix”
不改变原图的大小,从ImageView的左上角开始绘制原图,原图超过ImageView的部分作裁剪处理。
android:scaleType=”fitCenter”
把原图按比例扩大或缩小到ImageView的ImageView的高度,居中显示
android:scaleType=”fitEnd”
把原图按比例扩大(缩小)到ImageView的高度,显示在ImageView的下部分位置
android:scaleType=”fitStart”
把原图按比例扩大(缩小)到ImageView的高度,显示在ImageView的上部分位置
android:scaleType=”fitXY”
把原图按照指定的大小在View中显示,拉伸显示图片,不保持原比例,填满ImageView.
下面附上效果图:
原图为Pocoyo的头像,上图为原图的size大于ImageView的size,下图为原图的size小于ImageView的size
已经展示的很清楚了,也就是说我们的RoundImageView只支持fitxy跟martrix两种方式,我们看看ImageView的源码找找原因
问题1:为什么只支持fitxy跟matrix方式呢?
我们看看ImageView源码
private void configureBounds() { if (mDrawable == null || !mHaveFrame) { return; } final int dwidth = mDrawableWidth; final int dheight = mDrawableHeight; final int vwidth = getWidth() - mPaddingLeft - mPaddingRight; final int vheight = getHeight() - mPaddingTop - mPaddingBottom; final boolean fits = (dwidth < 0 || vwidth == dwidth) && (dheight < 0 || vheight == dheight); if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) { /* If the drawable has no intrinsic size, or we're told to scaletofit, then we just fill our entire view. */ mDrawable.setBounds(0, 0, vwidth, vheight); mDrawMatrix = null; } else { ...... } }
我们看到这么一行代码:
mDrawable.setBounds(0, 0, vwidth, vheight);
当为fitxy的时候给mDrawable(也就是我们设置的那张图片)设置了bounds为vwidth,vheight,也就是控件的宽高。所以fitxy时才会铺满整个屏幕的。
搞懂了fitxy,那么matrix又是怎么样的呢?
我们看看onDraw方法:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mDrawable == null) { return; // couldn't resolve the URI } if (mDrawableWidth == 0 || mDrawableHeight == 0) { return; // nothing to draw (empty bounds) } if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) { mDrawable.draw(canvas); } else { final int saveCount = canvas.getSaveCount(); canvas.save(); if (mCropToPadding) { final int scrollX = mScrollX; final int scrollY = mScrollY; canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop, scrollX + mRight - mLeft - mPaddingRight, scrollY + mBottom - mTop - mPaddingBottom); } canvas.translate(mPaddingLeft, mPaddingTop); if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); } mDrawable.draw(canvas); canvas.restoreToCount(saveCount); } }
有点长,我们看到有一行代码:
if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); }
canvas.concat(mDrawMatrix);是指给canvas做一些改变,比如缩放、平移…… 也就是说源码中通过我们设置的scaleType来通过算法计算mDrawMatrix ,然后再onDraw方法中赋给了canvas,但是我们重写了onDraw方法,也就是说mDrawMatrix 压根就不起作用了,所以当我们在RoundImageView中执行
//最后把我们准备好的Bitmap画在canvas上 canvas.drawBitmap(bitmap,0,0,null);
的时候,图片就是默认不缩放,原图从控件的左上角开始摆放的。
到此,我们终于弄懂了我们遇到的问题,既然遇到了,那我们就解决下问题。
我们看看ImageView到底是怎么缩放图片的:
private void configureBounds() { if (mDrawable == null || !mHaveFrame) { return; } final int dwidth = mDrawableWidth; final int dheight = mDrawableHeight; final int vwidth = getWidth() - mPaddingLeft - mPaddingRight; final int vheight = getHeight() - mPaddingTop - mPaddingBottom; final boolean fits = (dwidth < 0 || vwidth == dwidth) && (dheight < 0 || vheight == dheight); if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) { /* If the drawable has no intrinsic size, or we're told to scaletofit, then we just fill our entire view. */ mDrawable.setBounds(0, 0, vwidth, vheight); mDrawMatrix = null; } else { // We need to do the scaling ourself, so have the drawable // use its native size. mDrawable.setBounds(0, 0, dwidth, dheight); if (ScaleType.MATRIX == mScaleType) { // Use the specified matrix as-is. if (mMatrix.isIdentity()) { mDrawMatrix = null; } else { mDrawMatrix = mMatrix; } } else if (fits) { // The bitmap fits exactly, no transform needed. mDrawMatrix = null; } else if (ScaleType.CENTER == mScaleType) { // Center bitmap in view, no scaling. mDrawMatrix = mMatrix; mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f), Math.round((vheight - dheight) * 0.5f)); } else if (ScaleType.CENTER_CROP == mScaleType) { mDrawMatrix = mMatrix; float scale; float dx = 0, dy = 0; if (dwidth * vheight > vwidth * dheight) { scale = (float) vheight / (float) dheight; dx = (vwidth - dwidth * scale) * 0.5f; } else { scale = (float) vwidth / (float) dwidth; dy = (vheight - dheight * scale) * 0.5f; } mDrawMatrix.setScale(scale, scale); mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy)); } else if (ScaleType.CENTER_INSIDE == mScaleType) { mDrawMatrix = mMatrix; float scale; float dx; float dy; if (dwidth <= vwidth && dheight <= vheight) { scale = 1.0f; } else { scale = Math.min((float) vwidth / (float) dwidth, (float) vheight / (float) dheight); } dx = Math.round((vwidth - dwidth * scale) * 0.5f); dy = Math.round((vheight - dheight * scale) * 0.5f); mDrawMatrix.setScale(scale, scale); mDrawMatrix.postTranslate(dx, dy); } else { // Generate the required transform. mTempSrc.set(0, 0, dwidth, dheight); mTempDst.set(0, 0, vwidth, vheight); mDrawMatrix = mMatrix; mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType)); } } }
就是我们上面所说的,先通过我们设置的scaleType计算mDrawMatrix,
然后再onDraw方法中赋给canvans,再贴一遍ImageView的onDraw方法。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mDrawable == null) { return; // couldn't resolve the URI } if (mDrawableWidth == 0 || mDrawableHeight == 0) { return; // nothing to draw (empty bounds) } if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) { mDrawable.draw(canvas); } else { final int saveCount = canvas.getSaveCount(); canvas.save(); if (mCropToPadding) { final int scrollX = mScrollX; final int scrollY = mScrollY; canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop, scrollX + mRight - mLeft - mPaddingRight, scrollY + mBottom - mTop - mPaddingBottom); } canvas.translate(mPaddingLeft, mPaddingTop); if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); } mDrawable.draw(canvas); canvas.restoreToCount(saveCount); } }
我们自己重写了onDraw方法,也就是我们只需要像ImageView一样,把configureBounds方法搬到我们的控件中就可以了,好了,我们试试:
@Override protected void onDraw(Canvas canvas) { Bitmap bitmap = mWeakReference==null?null:mWeakReference.get(); if(bitmap==null || bitmap.isRecycled()){ //获取一下设置的图片资源 Drawable drawable=getDrawable(); if(drawable!=null){ //创建一个空白画布,用来画模板跟原图 bitmap=Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888); ////修改过的代码 Matrix matrix=null; Canvas dstCanvas=new Canvas(bitmap); dstCanvas.save(); if (getScaleType()==ScaleType.FIT_XY){ drawable.setBounds(0,0,getWidth(),getHeight()); matrix=null; }else{ matrix=new Matrix(); configureBounds(drawable,matrix); } if(matrix!=null){ dstCanvas.concat(matrix); } drawable.draw(dstCanvas); dstCanvas.restore(); ////修改过的代码 //画模板 if(mMaskBitmap==null||mMaskBitmap.isRecycled()){ mMaskBitmap=getShapeBitmap(); } dstCanvas.drawBitmap(mMaskBitmap,0,0,mPaint); mPaint.setXfermode(null); } } //最后把我们准备好的Bitmap画在canvas上 canvas.drawBitmap(bitmap,0,0,null); }
private void configureBounds(Drawable drawable, Matrix matrix) { ScaleType mScaleType = getScaleType(); //获取图片的宽高 int dwidth = drawable.getIntrinsicWidth(); int dheight = drawable.getIntrinsicHeight(); int vwidth =getWidth(); int vheight = getHeight(); if (ScaleType.MATRIX == mScaleType) { ///// } else if (ScaleType.CENTER_CROP == mScaleType) { float scale; float dx = 0, dy = 0; if (dwidth * vheight > vwidth * dheight) { scale = (float) vheight / (float) dheight; dx = (vwidth - dwidth * scale) * 0.5f; } else { scale = (float) vwidth / (float) dwidth; dy = (vheight - dheight * scale) * 0.5f; } matrix.setScale(scale, scale); matrix.postTranslate(Math.round(dx), Math.round(dy)); } else if (ScaleType.CENTER_INSIDE == mScaleType) { float scale; float dx; float dy; if (dwidth <= vwidth && dheight <= vheight) { scale = 1.0f; } else { scale = Math.min((float) vwidth / (float) dwidth, (float) vheight / (float) dheight); } dx = Math.round((vwidth - dwidth * scale) * 0.5f); dy = Math.round((vheight - dheight * scale) * 0.5f); matrix.setScale(scale, scale); matrix.postTranslate(dx, dy); } else { matrix.setRectToRect(new RectF(drawable.getBounds()), new RectF(0, 0, getWidth(), getHeight()), scaleTypeToScaleToFit(mScaleType)); } }
直接拖的ImageView的源码,不要问我算法为什么是这样,我也研究了蛮久,数学不好(^__^) 嘻嘻……
到这又郁闷了,scaleTypeToScaleToFit方法没法copy了,怎么办? 反射呗!说干咱就干。
private Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType mScaleType) { Class mClass=ImageView.class; try { Method method = mClass.getDeclaredMethod("scaleTypeToScaleToFit", new Class[]{ScaleType.class}); method.setAccessible(true); if(method!=null){ Matrix.ScaleToFit fit = (Matrix.ScaleToFit) (method.invoke(null, new Object[]{mScaleType})); return fit; } } catch (Exception e) { e.printStackTrace(); } return Matrix.ScaleToFit.FILL; }
不懂的童鞋自己去脑补下javase的东西哈!!
到此算是写完了,我们再次运行代码:
终于是完美的呈现了,从来没写过这么长的博客,小伙伴默默点个赞哈,大牛勿喷!!(^__^) 嘻嘻……
最后附上github地址:https://github.com/913453448/CircleViewDemo
- Android项目中遇到的坑之(Android圆角圆形图 二)
- Android项目中遇到的坑之(Android圆角圆形图 一)
- Android中自定义圆形图片(二)
- Android圆形ImageView(二)
- Android圆形头像的绘制(二)之自定义视图
- Android学习(二)--第二个项目遇到的问题
- Android中圆形的imageView
- Android Studio中使用过程中遇到的问题(二)--SVN的安装与使用以及关联本地项目
- Android开发之圆形图
- android蓝牙开发过程中遇到的问题(二)
- Android--面试中遇到的问题总结(二)
- Android项目中使用NativeLibCompression遇到的一些坑
- 在Android项目中,遇到过的坑
- Android 项目中遇到的坑,特此记录
- Android 圆形/圆角图片的方法
- Android中遇到的坑。
- Android之圆形(圆角)图片的实现(一)
- Android开源之圆形的ImageView
- 感谢
- [webGL学习]基于three.js构建WebGL实例第四讲
- 2016-10-10课后练习
- 关于机械臂逆运动学 jacobian矩阵
- 带头结点的链表的地址问题
- Android项目中遇到的坑之(Android圆角圆形图 二)
- Java中负数与符号扩展
- 【Python】NameError:name ‘xrange’ is not defined
- 161010
- ubuntu14.04+CUDA8下部署caffe的一些问题
- MPI_Bcast
- C++必知的几个知识点
- 独立按键实现秒表
- LayoutInflater.inflate()简单总结