经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android自定义View-使用BitmapShader实现圆形图片
来源:cnblogs  作者:余野AE  时间:2020/12/14 21:25:49  对本文有异议

前言

在软件开发过程中自定义View几乎必不可少,今天写下这篇博客记录自己学习自定义View的第一篇---利用BitmapShader做出圆形图片的效果

先上效果图

思路

整个代码主要使用了三个工具:Paint(画笔-用来绘图),BitmapShader(着色器-拉伸图片,画笔的助手),Martix(矩阵-用来缩放图片,着色器的小助手)

整体思路为:
1.重写onMeasure方法获取View宽高的最小值,并将最小值设置为该View的宽与高
2.获取图片资源,并用着色器拉伸放缩图片
3.将着色器配置给画笔,并在画布上将圆形图案画出来

代码实现

首先新建一个CircleImageView.java的类,让其继承androidx.appcompat.widget.AppCompatImageView

实现三个构造器方法,我们主要用到含两个参数的构造方法。

1.定义初始变量

  1. private Paint mPaint; //创建画笔
  2. private int mRadius; //图片的半径大小
  3. private Matrix mMartix; //缩放图片的矩阵
  4. private Bitmap mBitmap; //Bitmap图片资源
  5. private BitmapShader mBitmapShader; //Bitmap着色器,对bitmap进行拉伸

2.重写onMeasure()函数,获取并设置View的宽高

先通过获取图片的最短宽高让图片的宽度与高度保持一致,除以2后即为半径大小

  1. //通过获取图片的最短宽高让图片的宽高保持一致,除以2后即为半径大小
  2. mRadius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2;

然后再重写设置视图的宽高

  1. //重新设置视图的宽高
  2. setMeasuredDimension(mRadius * 2, mRadius * 2);

onMeasure()部分的完整代码为:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. mRadius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2;
  5. setMeasuredDimension(mRadius * 2, mRadius * 2);
  6. }

3.进行初始化操作

在第二个构造器中添加init()函数

  1. public CircleImageView(Context context, @Nullable AttributeSet attrs) {
  2. super(context, attrs);
  3. init();
  4. }

新建init()函数,在其中进行初始化操作

第一步先判断是否有图片资源存在,如果没有话就不继续执行后面的方法了

  1. if (getDrawable() == null){
  2. return;
  3. }

接下来我们先对画笔,矩阵进行初始化设置,并将Drawable转化为Bitmap

  1. //实例化画笔
  2. mPaint = new Paint();
  3. //实例化矩阵
  4. mMartix = new Matrix();
  5. //获取图片资源,并将drawable图片转化为bitmap图片,便于我们后续的画图
  6. mBitmap = drawableToBitmap(getDrawable());

这里需要用到private void drawableToBitmap(Drawable drawable);函数,将Drawable转化为Bitmap,因为Bitmap一般用来做空白画布画图

在转换函数中我们先判断传进来的drawable是否为BitmapDrawable的实例,如果该drawable为BitmapDrawable的实例,就可以直接进行强制转换

  1. if (drawable instanceof BitmapDrawable){
  2. BitmapDrawable bd = (BitmapDrawable) drawable;
  3. return bd.getBitmap();
  4. }

如果不是的话,就可以通过对应的Bitmap画布把drawable内容画到画布中

  1. //取得drawable的宽和高
  2. int width = drawable.getIntrinsicWidth();
  3. int height = drawable.getIntrinsicHeight();
  4. //建立对应的Bitmap
  5. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  6. //建立对应bitmap的画布
  7. Canvas canvas = new Canvas(bitmap);
  8. //把drawable内容画到画布中去
  9. drawable.setBounds(0, 0, width, height);
  10. drawable.draw(canvas);
  11. return bitmap;

完整转换代码如下:

  1. private Bitmap drawableToBitmap(Drawable drawable){
  2. if (drawable instanceof BitmapDrawable){
  3. BitmapDrawable bd = (BitmapDrawable) drawable;
  4. return bd.getBitmap();
  5. }
  6. else {
  7. //取得drawable的宽和高
  8. int width = drawable.getIntrinsicWidth();
  9. int height = drawable.getIntrinsicHeight();
  10. //建立对应的Bitmap
  11. Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  12. //建立对应bitmap的画布
  13. Canvas canvas = new Canvas(bitmap);
  14. //把drawable内容画到画布中去
  15. drawable.setBounds(0, 0, width, height);
  16. drawable.draw(canvas);
  17. return bitmap;
  18. }
  19. }

转换为Bitmap后,我们回到init()函数,继续进行对着色器的初始化

新建Bitmap着色器,传入bitmap对象(避免在onDraw函数中初始化),其中后两个参数为平铺模式

TileMode有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像

  1. //实例化着色器
  2. mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
  3. Shader.TileMode.CLAMP);

至此,初始化设置完成。

4.重写onDraw()函数,进行绘制

在绘制函数中主要设置矩阵mMartix,着色器mBitmapShader和画笔mPaint三者的属性

首先我们要为矩阵计算出偏移值,防止因图片的宽高大于View的宽高而造成拉伸效果,即只在圆圈内显示一部分的图像,而不能显示完全

取bitmap宽高的最小值作为基准,计算缩放比例(必须为浮点数) mRadius*2.0f 是指裁剪后View的宽度,在onMeasure()方法里

  1. //图片的缩放比例
  2. float mScale = (mRadius * 2.0f) / Math.min(mBitmap.getWidth(), mBitmap.getHeight());

然后设置矩阵偏移度

  1. //设置矩阵的偏移度
  2. mMartix.setScale(mScale, mScale);

接着我们让着色器装备上设置好的矩阵,这样就不会出现无法显示完图片的问题啦

  1. //设置着色器的矩阵
  2. mBitmapShader.setLocalMatrix(mMartix);

最后,把我们的着色器装配给画笔

  1. //把着色器配给我们的画笔
  2. mPaint.setShader(mBitmapShader);

然后就是整个绘制流程的最后一步啦!调用drawCircle函数用画布把圆画出来

  1. //调用drawCircle函数用画布把圆画出来
  2. canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);

onDraw()函数整体代码如下

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. //取bitmap宽高的最小值作为基准,计算缩放比例(必须为浮点数) mRadius*2.0f 是指裁剪后View的宽度,在onMeasure()方法里
  4. float mScale = (mRadius * 2.0f) / Math.min(mBitmap.getWidth(), mBitmap.getHeight()); //图片的缩放比例
  5. //接下来使用矩阵防止因view的宽高大于bitmap的宽高而造成拉伸效果
  6. //设置矩阵的偏移度
  7. mMartix.setScale(mScale, mScale);
  8. //设置着色器的矩阵
  9. mBitmapShader.setLocalMatrix(mMartix);
  10. //把着色器配给我们的画笔
  11. mPaint.setShader(mBitmapShader);
  12. //调用drawCircle函数用画布把圆画出来
  13. canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
  14. }

至此函数部分已完全写完,接下来我们就可以直接去xml文件里使用我们自定义的View了

  1. <com.aefottt.seventhwork.ui.view.CircleImageView
  2. android:layout_width="0dp"
  3. android:layout_weight="1"
  4. android:layout_height="100dp"
  5. android:layout_margin="15dp"
  6. android:src="@mipmap/aefottt"/>
  7. <com.aefottt.seventhwork.ui.view.CircleImageView
  8. android:layout_width="0dp"
  9. android:layout_weight="2"
  10. android:layout_height="100dp"
  11. android:layout_margin="15dp"
  12. android:src="@mipmap/aefottt"/>
  13. <com.aefottt.seventhwork.ui.view.CircleImageView
  14. android:layout_width="0dp"
  15. android:layout_weight="3"
  16. android:layout_height="150dp"
  17. android:layout_margin="15dp"
  18. android:src="@mipmap/aefottt"/>

圆形图片的绘制至此结束,然后运行你的app,你会发现有三张圆圆的图片显示在你的屏幕上呀。

接下来有时间会在这篇文章后面继续写圆角图片的绘制。

有问题欢迎大家在评论区讨论呀

原文链接:http://www.cnblogs.com/aefottt/p/14135414.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号