博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
圆形图片的制作
阅读量:6786 次
发布时间:2019-06-26

本文共 7196 字,大约阅读时间需要 23 分钟。

近期又在啃《Android开发艺术探索》这本书,最近看到了第六章节—Android中的Drawable。我写博客的风格不喜欢一味的介绍理论知识,更喜欢从实战的角度去学习,在敲代码的过程中去补充理论知识,根据实际情况做出分析,最后实现想要的效果。本文就从制作圆形头像的角度,来学习Android中的Drawable的那些事。

一.准备工作

Drawable有很多种,表示的是一种可以在Canvas上进行绘制的抽象的概念,它的种类有很多种,最常见的颜色和图片都可以是一个Drawable。它是所有Drawable对象的基类,每个具体的Drawable都是它的子类。比如下文提到的BitmapDrawable。

BitmapDrawable是一种最简单的Drawable,它表示的就是一张图片,在实际开发中应用也是最广泛的,我们可以直接引用原始图片即可获取。

回到需求上,我们要制作一个圆形头像,首先需要一张图片,最终以圆形的方式展现出来。

这是我在网上找的一张图片:

这里写图片描述

制作圆形图片,最理想的效果是原始图片能够是正方形的,这样图片裁剪成圆形以后才会显得对称。而提供给我们的原始图片很有可能不是正方形的,比如上图,所以我们首先要加工这张图片,使成为正方形图片。

布局文件:

布局文件中,上面是我们的原始图片,下面是我们处理以后的图片,看看点击事件做了什么:

btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Bitmap bitmap = ((BitmapDrawable) myCircleImageView.getDrawable()).getBitmap();                Matrix matrix = new Matrix();                float size = Math.min(bitmap.getWidth(), bitmap.getHeight());                //x缩放比例                float x = size / bitmap.getWidth();                //y缩放比例                float y = size / bitmap.getHeight();                matrix.setScale(x, y);                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);                img.setImageBitmap(newBitmap);            }        });

首先获取当前ImageView的Bitmap,关于ImageView转换为Bitmap,大家可以参考这篇博客:

然后构造一个矩阵Matrix,计算并设置好缩放比例,然后调用

createBitmap(Bitmap source, int x, int y, int width, int height,

Matrix m, boolean filter)

方法生成新的Bitmap。看看这个方法具体干了什么:

这里写图片描述

这是官方文档解释,source代表原始图片的Bitmap;x,y代表X,Y方向上的起始位置;width,height代表X,Y方向需要处理的宽度与高度;m代表图片处理的矩阵;,filter参数为true表示进行滤波处理,有助于改善新图像质量,flase代表不做过滤处理。

看看处理后的效果:

这里写图片描述

OK,图片的前期准备工作已经做好了,现在开始制作圆形头像了。

二.XferMode方法制作圆形图片

Xfermode有三个子类 :
AvoidXfermode ,PixelXorXfermode,PorterDuffXfermode,其中前两个类在API 16被遗弃了 。PorterDuffXfermode类主要用于计算图形合成时的图像过渡模式 ,一共有16条规则。然后调用 paint.setXfermode(XferMode)方法设置图像的过渡模式,这样就可以完成一些复杂的效果。先看看有哪些模式:

这里写图片描述

每种模式代表的含义如下:

1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色

大家也可以参考这篇文章:

这里我们结合圆形图像的例子看看怎么使用:

//缩放以后的bitmap                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);                int width = newBitmap.getWidth();                int height = newBitmap.getHeight();                //圆形bitmap                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);                Canvas canvas = new Canvas(circleBitmap);                Paint paint = new Paint();                paint.setAntiAlias(true);                paint.setColor(Color.BLACK);                canvas.drawCircle(width / 2, height / 2, width / 2, paint);                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);                paint.setXfermode(porterDuffXfermode);                canvas.drawBitmap(newBitmap, 0, 0, paint);                circleImg.setImageBitmap(circleBitmap);

得到缩放以后的Bitmap以后,创建一个Canvas对象,首先绘制了一个黑色实心圆,然后设置Xfermode为PorterDuff.Mode.SRC_IN,最后绘制缩放以后的Bitmap。根据这种模式的定义:取两层绘制交集并显示上层,可以得到我们的圆形头像。最后实现的效果如下:

这里写图片描述

三.BitmapShader方法制作圆形图片

BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置,BitmapShader的构造方法如下:

mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);

参数1:bitmap

参数2,参数3:TileMode;
TileMode的取值有三种:
CLAMP 拉伸 拉伸的是图片最后的那一个像素;横向的最后一个横行像素,不断的重复,纵项的那一列像素,不断的重复
REPEAT 重复 就是横向、纵向不断重复这个bitmap
MIRROR 镜像 横向不断翻转重复,纵向不断翻转重复

关于BitmapShader可参考:

这里我们结合圆形图像的例子看看怎么使用:

//缩放以后的bitmap                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);                int width = newBitmap.getWidth();                int height = newBitmap.getHeight();                //圆形bitmap                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);                Canvas canvas = new Canvas(circleBitmap);                Paint paint = new Paint();                paint.setAntiAlias(true);                paint.setColor(Color.BLACK);                /**第一种方式**///                canvas.drawCircle(width / 2, height / 2, width / 2, paint);//                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//                paint.setXfermode(porterDuffXfermode);//                canvas.drawBitmap(newBitmap, 0, 0, paint);                /**第二种方式**/                BitmapShader bitmapShader = new BitmapShader(newBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);                paint.setShader(bitmapShader);                canvas.drawCircle(width / 2, height / 2, width / 2, paint);                circleImg.setImageBitmap(circleBitmap);

得到缩放以后的Bitmap以后,创建一个Canvas对象,初始化BitmapShader,画笔设置Shader,最后在canvas里面进行画圆就行了。效果与第一种方式实现的一样,就不重复贴图了。

四.ClipPath方法制作圆形图片

使用clipPath的方法进行切割,来实现圆角图片,具体可参考:

这里我们结合圆形图像的例子看看怎么使用:

//缩放以后的bitmap                Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);                int width = newBitmap.getWidth();                int height = newBitmap.getHeight();                //圆形bitmap                Bitmap circleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);                Canvas canvas = new Canvas(circleBitmap);                Paint paint = new Paint();                paint.setAntiAlias(true);                paint.setColor(Color.BLACK);                /**第一种方式**///                canvas.drawCircle(width / 2, height / 2, width / 2, paint);//                PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//                paint.setXfermode(porterDuffXfermode);//                canvas.drawBitmap(newBitmap, 0, 0, paint);                /**第二种方式**///                BitmapShader bitmapShader = new BitmapShader(newBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);//                paint.setShader(bitmapShader);//                canvas.drawCircle(width / 2, height / 2, width / 2, paint);//                circleImg.setImageBitmap(circleBitmap);                /**第三种方式**/                Path path = new Path();                //按照顺时针方向添加一个圆                path.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);                canvas.save();                //设置为在圆形区域内绘制                canvas.clipPath(path);                canvas.drawBitmap(newBitmap, 0, 0, paint);                canvas.restore();                circleImg.setImageBitmap(circleBitmap);

得到缩放以后的Bitmap以后,创建一个Canvas对象,设置为在圆形区域内绘制,最后在canvas里面绘制Bitmap。效果与第一种方式实现的一样,就不重复贴图了。

当然,要实现其他形状图片,其实很简单,每种方法稍微改变一下就行,只要先绘制出不同的形状,原理还是和这个一样。

OK,源码已同步上传至github,欢迎star,fork,提issues,一起交流进步!

你可能感兴趣的文章
jmeter用BeanShell调用jar包对HTTP请求中的参数进行MD5加密
查看>>
判断页数及切换
查看>>
GraphQL ---02 GraphQL和C#结合的实战项目
查看>>
Vmware虚拟机三种网络模式详解
查看>>
【已解决】如图,说我磁盘不够,看到var目录下有的个隐藏文件夹占了46G,不知道怎么删除...
查看>>
[LintCode] O(1)检测2的幂次
查看>>
BZOJ3295:[CQOI2011]动态逆序对——题解
查看>>
Office Online简介
查看>>
房天下爬虫
查看>>
常用Shell脚本命令(备忘)
查看>>
Python中的__init__,__call__
查看>>
如何设置Navicat的显示字体与字体大小?
查看>>
【转】HttpServlet详解
查看>>
项目 04 数据库迁移工具,增加用户系统-用户中心
查看>>
程序员小笑话
查看>>
DataTable AsEnumerable 的使用
查看>>
JS滚轮事件(mousewheel/DOMMouseScroll)了解
查看>>
GDI+与GDI屏幕抓图比较
查看>>
mysql中date_add()函数的使用?
查看>>
Window系统查找并关闭进程中的端口
查看>>