在Android开发中,圆形图片是很常见的,例如淘宝的宝贝,QQ的联系人头像等都是圆形的图片,

但是Android原生的ImageView又不能显示圆形的图片,这就需要我们自己去实现一个圆形图了

一、自定义View实现圆形图

我们可以去改造Android系统自带的ImageView来让它显示圆形图片,具体思路是利用画笔的层叠属性,在图片的底部绘制一个圆形,然后显示上下两层的交集部分,就可以做出一个圆形的ImageView了

1.1继承ImageView

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ImageView;/*** Created by ChenFengYao on 16/3/15.*/
public class RoundImageView extends ImageView {private Paint paint;public RoundImageView(Context context) {super(context);paint  = new Paint();//初始化画笔对象}public RoundImageView(Context context, AttributeSet attrs) {super(context, attrs);paint  = new Paint();//初始化画笔对象}public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint  = new Paint();//初始化画笔对象}
}

继承ImageView复写其中的构造方法,并在构造方法里对画笔对象进行初始化

1.2复写onDraw方法

 @Overrideprotected void onDraw(Canvas canvas) {Drawable drawable = getDrawable();if (null != drawable) {Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();//核心代码Bitmap b = getCircleBitmap(bitmap);paint.reset();canvas.drawBitmap(b,0,0,paint);} else {super.onDraw(canvas);}}

onDraw方法即图片绘制的时候系统所调用的方法,在该方法内部首先去判断是否设置了图片的src,如果能拿到改View设置的图片,则将它转换成圆形图片,如果没有设置的话,则不做任何操作,直接调用父类的onDraw方法

1.2getCircleBitmap

private Bitmap getCircleBitmap(Bitmap bitmap){Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(output);Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());paint.setAntiAlias(true);canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getHeight() / 2, paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(bitmap, rect, rect, paint);//将图片画出来return output;
}

这是获取圆形图的方法,目的是将我们自定义的View中的图片,转化成圆形的Bitmap,这里需要Canvas对象,首先画一个圆形的底层,再在其上放上我们的图片,通过设置画笔的paint的Xfermode属性,该属性是用来设置前后图层的显示关系的,这是设置Mode.SRC_IN,的意思是输出的范围是底层图形的范围,而显示的内容是上层的内容

1.2.1paint.setXfermode()

Xfermode有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种,简单来说,可以理解成图片的叠加方式.
我们可以看一下图片的16中叠加方式

PorterDuff.Mode.CLEAR

所绘制不会提交到画布上。

PorterDuff.Mode.SRC

显示上层绘制图片

PorterDuff.Mode.DST

显示下层绘制图片

PorterDuff.Mode.SRC_OVER

正常绘制显示,上下层绘制叠盖

PorterDuff.Mode.DST_OVER

上下层都显示。下层居上显示

PorterDuff.Mode.SRC_IN

取两层绘制交集。显示上层

PorterDuff.Mode.DST_IN

取两层绘制交集。显示下层

PorterDuff.Mode.SRC_OUT

取上层绘制非交集部分

PorterDuff.Mode.DST_OUT

取下层绘制非交集部分

PorterDuff.Mode.SRC_ATOP

取下层非交集部分与上层交集部分

PorterDuff.Mode.DST_ATOP

取上层非交集部分与下层交集部分

PorterDuff.Mode.XOR

取两层绘制非交集。两层绘制非交集

PorterDuff.Mode.DARKEN

上下层都显示。变暗

PorterDuff.Mode.LIGHTEN

上下层都显示。变亮

PorterDuff.Mode.MULTIPLY

取两层绘制交集

PorterDuff.Mode.SCREEN

上下层都显示

1.2.2Canvas

Canvas类可以绘制各种的图形,在绘制的时候会将绘制好的内容保存在Canvas的内部,可以将所绘制的内容输出为一张Bitmap,这张Bitmap即在new Canvas的时候通过构造方法传进去.而在onDraw方法中传入的Canvas则会在绘制完毕后,直接将内部的内容输出到屏幕上的.

1.3测试

写好了之后,我们来测试一下
<com.lanou.chenfengyao.temproundimageview.RoundImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/test_img"/>

看 图片已经被处理成圆形的了

1.4 添加功能

我们希望可以用我们自己的RoundImageView来实现即可以显示正常的ImageView也可以显示圆形图片的功能,最好可以能用Java代码动态控制.于是我们添加一个自定义属性
首先在values下新建attrs.xml 代码如下
<resources><declare-styleable name="RoundImageView"><attr name="is_round" format="boolean" /></declare-styleable>
</resources>
可以看到 我们定义了一条自定义属性:is_round 它是一个boolean值的属性,当属性是false的时候 我们就显示一个正常的图片,当属性是true的时候,则显示一个圆形图片
在RoundImageView中添加一个变量
private boolean isRound;

然后在构造方法里提取这条属性,如果没有提取到,默认值设置为true,让它默认就可以显示圆角图片

public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();//初始化画笔对象TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);isRound = typedArray.getBoolean(R.styleable.RoundImageView_is_round, true);
}

为了增加实用性 我们改造一下剩下的构造方法

public RoundImageView(Context context) {this(context, null);
}public RoundImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);
}
接下来在onDraw方法里进行一次判断,如果需要显示圆形图,才显示圆形图
 @Overrideprotected void onDraw(Canvas canvas) {Drawable drawable = getDrawable();if (null != drawable && isRound) {Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();//核心代码Bitmap b = getCircleBitmap(bitmap);paint.reset();canvas.drawBitmap(b, 0, 0, paint);b.recycle();} else {super.onDraw(canvas);}}

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">测试一下,我们将我们的组件的is_round属性改成false看看效果</span>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.lanou.chenfengyao.temproundimageview.MainActivity"><com.lanou.chenfengyao.temproundimageview.RoundImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/test_img"app:is_round="false"/>
</RelativeLayout>

注意,我们自定义的属性,命名空间不要忘记了

来看看效果

可以看到,现在的RoundImageView就和正常的ImageView的效果是一样的啦.

现在我们再写一个方法能让RoundImgeView动态的改变圆形或是正常的,在RoundImageView里添加方法
public void setIsRound(boolean isRound) {this.isRound = isRound;invalidate();}

现在我们在Activity里放上一个按钮,点击它切换显示模式,来测试一下


可以看到 我们的图片可以通过Java代码来动态的切换正常模式和圆形图片啦

二、使用Fresco显示圆形图片

Fresco是FaceBook推出的专门用来加载图片的类库,它可以加载网络图片,并且有丰富的效果,并且最重要的是,它具有中文文档!
文档地址http://www.fresco-cn.org/
根据文档我们首先在gradle里加上
compile 'com.facebook.fresco:fresco:0.9.0+'

另外Fresco在使用的时候需要对其进行初始化,可以在需要的Activity里的onCreate方法里添加

Fresco.initialize(this);

建议将这行代码添加到Application里进行全局的初始化

在使用起来就变得很简单了,只需要在xml里添加
<com.facebook.drawee.view.SimpleDraweeViewfresco:roundAsCircle = "true"fresco:actualImageScaleType="centerInside"fresco:roundingBorderColor="@color/colorAccent"fresco:roundingBorderWidth="1dp"android:layout_width="match_parent"android:layout_height="match_parent"fresco:backgroundImage="@mipmap/test_img"/>

并且不要忘记命名空间

xmlns:fresco="http://schemas.android.com/apk/res-auto"

看一下效果

可以看到出现了圆形图片,并且还有1dp的红色边框

2.1一些坑

Fresco在这种使用方式的时候有一些坑是值得注意的,首先根据官方的说法,会在后续的版本中不再继承自ImageView,所以不建议使用ImageView的一些属性和方法,例如src等.
第二,该空间无法使用wrap_content的方式来指定宽高,这点略坑...

三、利用sharp做圆形图

我们也可以使用ImageView和sharp来完成一个圆形图片的效果,首先在drawable里新建circle.xml

<shapeandroid:innerRadius="0dp"android:shape="ring"android:thicknessRatio="1"android:useLevel="false"xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="@android:color/transparent" /><strokeandroid:width="68dp"android:color="#FFFFFFFF" />
</shape>

让shape是ring即环形,并且设置填充颜色为白色,线宽需要根据图片自己调整

然后再drable里新建round_layers.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@mipmap/test_img" /><item android:drawable="@drawable/circle" />
</layer-list>

layer-list的意思是让ImageView中显示的图片产生一个叠加的效果,越靠下写的,在显示的时候就越靠上层

最后让ImageView使用该xml
<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/round_layers"/>

看一下效果吧

实际上,该方法的原理就是在正常的ImageView上再叠加了一个白色的环形图形,这样显示的效果就是圆形图片了.但是缺点也是显而易见的,即需要手动的调节环形的粗细,比较难控制

以上就是Android中实现圆形图片的几种方案了,各有优缺点,还有更好的解决方案,可以留言讨论~

Android中圆形图的几种实现方式相关推荐

  1. Android中夜间模式的三种实现方式

    参考:https://www.jianshu.com/p/f3aaed57fa15 在本篇文章中给出了三种实现日间/夜间模式切换的方案: 使用 setTheme 的方法让 Activity 重新设置主 ...

  2. android 软件 加密方法,Android中WIFI常见的几种加密方式(详细)

    系统设置中WIFI热点的加密方式,添加新的WIFI和连接WIFI的时候,需要在程序中配置相应的参数,可以打开自己的手机对着看 包:android.net.wifi.WifiConfiguration  ...

  3. Android中WIFI常见的几种加密方式(详细)

    系统设置中WIFI热点的加密方式,添加新的WIFI和连接WIFI的时候,需要在程序中配置相应的参数,可以打开自己的手机对着看 包:android.net.wifi.WifiConfiguration  ...

  4. [译] 绘制路径:Android 中矢量图渲染

    原文地址:Draw a Path: Rendering Android VectorDrawables 原文作者:Nick Butcher 译文出自:掘金翻译计划 本文永久链接:github.com/ ...

  5. Android 圆形头像的两种实现方式

    Android 圆形头像的两种实现方式 前言 这篇博客只是为了做一个记录而已,方便而后查询,核心代码都是直接采用鸿洋博客里面的代码的. 圆形头像在实际开发中实际很常见,一般来说,主要有两种实现方式: ...

  6. Android实现圆形图像的两种方法(Glide和Picasso)

    Android实现圆形图像的两种方法 先上效果图 Glide Picasso CircleTransform.java(圆形图片工具类) 先上效果图 Glide 在app的build.gradle中引 ...

  7. lisp遍历表中所有顶点_三十张图片让你彻底弄明白图的两种遍历方式:DFS和BFS...

    1 引言   遍历是指从某个节点出发,按照一定的的搜索路线,依次访问对数据结构中的全部节点,且每个节点仅访问一次.   在二叉树基础中,介绍了对于树的遍历.树的遍历是指从根节点出发,按照一定的访问规则 ...

  8. android xpath解析xml,Android 中处理 XML 的四种方式-DOM

    Android 中处理 XML 的几种方式连载中,我们就不介绍合成 XML 了,因为合成 XML 可以直接拼接字符串,虽然看起很不高大上,但却很有效.我们主要介绍如何取 XML 中的值. 适用 DOM ...

  9. Android中播放音乐的几种方式

    Android中播放音乐的几种方式 前言 前几天一直在研究RxJava2,也写了记录了几篇博客,但因为工作任务原因,需要研究音频相关的知识,暂时放下Rxjava,本文的demo中,MediaPalye ...

最新文章

  1. 工作中MySql的了解到的小技巧
  2. 设计模式 之 建造者
  3. Python_03-数据类型
  4. Arduino可穿戴教程之第一个程序——选择端口(三)
  5. 用户控件(.ascx)调用网页(.aspx)的方法
  6. 下载达 10 万次的 IDEA 插件,K8s 一键部署了解一下?
  7. 认识因特网络(小学计算机课件),小学信息技术认识因特网ppt课件.ppt
  8. (王道408考研数据结构)第五章树-第四节2:平衡二叉树(AVL)及其旋转
  9. 【面试】面试文章积累
  10. 概率图模型(03): 模板模型(动态贝叶斯, 隐马尔可夫和Plate模型)
  11. Linux/Ubuntu20 安装 TP-link(RTL8812AU) 无线网卡驱动
  12. LabVIEW 2021 工具包
  13. Ubuntu登录界面键盘鼠标失灵
  14. Mac 安装LaTeX教程 mactex+sublime+skim
  15. Unity项目美术资源优化篇
  16. 【Data URL】【RE】【bugku】逆向入门writeup
  17. Openwrt Kernel panic - not syncing: Fatal exception 解决方案
  18. Spring JDBC与事务管理
  19. 如何进入游戏行业成为一个程序员
  20. SLM328美格4G模组SDK开发笔记

热门文章

  1. 曾鸣:取势、明道、立理、优术
  2. java app 图标_App 更换应用图标
  3. Linux/Centos: OpenSSL中文手册之EVP库详解
  4. 中南大学计算机考研资料汇总
  5. 总线(二)CAN通讯协议介绍
  6. 无人机电力巡线和无人机电力巡检在三维地理信息电子沙盘系统中的应用解决方案
  7. Arcgis中如何实现线转面
  8. 手机端移动端的前端原生js裁剪图片上传
  9. ISV是Independent Software Vendors 的英文缩写,意为“独立软件开发商”
  10. 为什么学微电子的都怕掉进材料的坑?