圆形图片的制作

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

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

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

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

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

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

这里写图片描述

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

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_third"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="org.tyk.android.artstudy.ThirdActivity">


    <ImageView
        android:id="@+id/my_circle_img"
        android:layout_width="100dp"
        android:layout_height="150dp"
        android:layout_marginTop="10dp"
        android:src="@drawable/k" />


    <ImageView
        android:id="@+id/second_img"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginTop="10dp" />

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="缩放" />

</LinearLayout>

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

        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,大家可以参考这篇博客:

Android 怎么把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
取两图层全部区域,交集部分变为透明色

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

各个击破搞明白PorterDuff.Mode

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

                //缩放以后的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可参考:
自定义控件其实很简单1/3

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

                //缩放以后的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的方法进行切割,来实现圆角图片,具体可参考:

Path图形与逻辑运算

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

                //缩放以后的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,一起交流进步!

https://github.com/18722527635/AndroidArtStudy

目录
相关文章
|
25天前
|
定位技术
Cesium修改地球的贴图为视频或者图片
这篇文章说明了如何在Cesium中修改地球的贴图,替换为自定义的图像或视频纹理。
30 1
Cesium修改地球的贴图为视频或者图片
Photoshop制作漂亮白色荧光文字图片
Photoshop制作漂亮白色荧光文字图片
70 0
|
6月前
|
数据可视化 定位技术 开发者
黑白或彩色线稿地图设计定制装饰画中线条轮廓素材底图获取方法合集
黑白或彩色线稿地图设计定制装饰画中线条轮廓素材底图获取方法合集
|
编解码 Windows
用文字制作成图片
最近呢,我一个朋友要过生日,我像给她一个硬核的生日祝福。然后就想到了用文字拼成她的QQ头像
156 0
用文字制作成图片
|
前端开发 Android开发
制作圆形图片,你会以下几种?
制作圆形图片,你会以下几种?
制作圆形图片,你会以下几种?
|
前端开发
制作了一个马赛克图片转换器
制作了一个马赛克图片转换器,可以将图片转换成马赛克风格,并可转换为 css box-shadow 进行输出。
|
前端开发 算法
制作了一个马赛克图片转换器 - 实现篇
上文有讲到我制作了一个马赛克图片转换器,可以将图片转换成马赛克风格,并可转换为 css box-shadow 进行输出。
|
Windows
利用Adorner制作用于图像裁切的选择框
原文:利用Adorner制作用于图像裁切的选择框 前天,我写了一篇“使用Adorner显示WPF控件的边界点”的文章。这次,使用从Adorner继承来写一个用于图像裁切的选择框。
779 0
|
前端开发 Android开发
利用PorterDuffXfermode绘制图片文字
PorterDuffXfermode是Android中用来对图层进行操作的类,类似于数学中的交集、并集,将上层(src)和下层(dst)进行特定的方式进行混合显示。
1049 0