接着上一篇的问题来研究研究:
**问题来了:效果是有了,但有发现么?我设置的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 toscaletofit, 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方法:

@Overrideprotected 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 toscaletofit, 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方法。

@Overrideprotected 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方法搬到我们的控件中就可以了,好了,我们试试:

@Overrideprotected 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圆角圆形图 二)相关推荐

  1. android项目中使用的服务器上,android 开发中使用okhttp上传文件到服务器

    开发android手机客户端,常常会需要上传文件到服务器,比如:你手机里的照片. 使用okhttp会是一个很好的选择.它使用很简单,而且运行效率也很高. 首先,在 app/build.gradle 的 ...

  2. flutter打开android界面,在已有Android项目中使用Flutter

    实现效果,在已存在的android项目中接入flutter,即android调用开启flutter页面(使用android打开flutter的指定页面),flutter调用原生android方法 步骤 ...

  3. XamarinSQLite教程在Xamarin.Android项目中使用数据库

    XamarinSQLite教程在Xamarin.Android项目中使用数据库 在Xamarin.Android项目中使用预设数据库的具体操作步骤如下: (1)创建一个Xamarin.Android项 ...

  4. xamarin怎么调用java的_XamarinSQLite教程在Xamarin.Android项目中使用数据库

    XamarinSQLite教程在Xamarin.Android项目中使用数据库 在Xamarin.Android项目中使用预设数据库的具体操作步骤如下: (1)创建一个Xamarin.Android项 ...

  5. android使用webview上传文件,Android项目中如何在webview页面中上传文件

    Android项目中如何在webview页面中上传文件 发布时间:2020-11-26 15:56:27 来源:亿速云 阅读:68 作者:Leah 本篇文章为大家展示了Android项目中如何在web ...

  6. Android项目中创建编译期的注解

    ==注解 生命周期为RetentionPolicy.RUNTIME,可在运行时通过反射获取. 生命周期为RetentionPolicy.CLASS, 编译期处理的注解,可以使用APT(Annotati ...

  7. Android项目中出现的Plugin with id ‘kotlin-android‘ not found解决方法

    Android项目中出现的Plugin with id 'kotlin-android' not found解决方法 参考文章: (1)Android项目中出现的Plugin with id 'kot ...

  8. XamarinSQLite教程在Xamarin.Android项目中提取数据库文件

    XamarinSQLite教程在Xamarin.Android项目中提取数据库文件 由于不能直接打开该文件,开发者需要先将数据库文件从Android系统中提取出来.操作步骤如下. (5)选择MyDoc ...

  9. XamarinSQLite教程在Xamarin.Android项目中定位数据库文件

    XamarinSQLite教程在Xamarin.Android项目中定位数据库文件 实际开发中,经常需要验证数据库操作的正确性.这个时候,需要打开数据库文件,进行确认.下面是如何找到MyDocumen ...

最新文章

  1. mysql5.6.37驱动_mysql 5.6.37(zip)下载安装配置图文教程
  2. 用相对路径有时居然是这样,,加上%=basePath%
  3. C语言常用排序方法大全
  4. 浅析Codewarrior、IAR和Keil MDK三大开发环境优缺点
  5. LiveMigration之四配置高可用虚拟机
  6. 让人迷茫的三十岁,从专业技能、行业知识和软实力的人才三角谈起
  7. boost::gil模块计算直方图的测试程序
  8. 用js控制选择CheckBoxList
  9. 2021年广东工业大学第十五届文远知行杯程序设计竞赛(同步赛)C题 图墙+拉格朗日四平方数和定理
  10. python中if嵌套语句的作用_讲解Python中if语句的嵌套用法
  11. 用python海龟画图_天呐!python 的乌龟绘图怎么用啊!?
  12. PHP之数组函数(2)
  13. 几种常见排序算法的时间复杂度和简单描述
  14. Graphics.DrawLine 方法
  15. java jdom格式,java使用jdom生成xml格式文件
  16. EXCEL长数字显示和转化为文本
  17. 商业研究(17):以小见大,看互联网经济(4个股权众筹平台,4个领域,10个项目,8个图)
  18. 在无外网虚拟机CentOS7下安装金山wps-office最新版(超详细小白教程)
  19. android虚拟机固定横屏幕竖屏,用VBox虚拟机安装Android 屏幕90度翻转竖屏设置
  20. nginx配置别名与前后端根目录名关联

热门文章

  1. R plot图片背景设置为透明_R语言实战 牛国庆
  2. python关键字数据驱动_携程大牛谈自动化测试里的数据驱动和关键字驱动思路的理解...
  3. linux系统查看机器硬件信息,linux系统查看硬件信息的方法
  4. initialcontext java_缺少InitialContext定义时要使用的Java运行时异常
  5. Arm Cortex-A35 性能对比
  6. Optional 最佳实践
  7. SpringBoot中使用Easyexcel实现Excel导入导出功能(一)
  8. 【复现1】CADTransformer: Panoptic Symbol Spotting Transformer for CAD Drawings
  9. 将windows系统主机上的文件拷贝到Linux系统中;将Linux系统中的文件粘贴到Windows主机中
  10. halcon显示坐标_HALCON深度学习工具0.4 早鸟版发布了