Android中圆形图的几种实现方式
在Android开发中,圆形图片是很常见的,例如淘宝的宝贝,QQ的联系人头像等都是圆形的图片,
但是Android原生的ImageView又不能显示圆形的图片,这就需要我们自己去实现一个圆形图了
一、自定义View实现圆形图
我们可以去改造Android系统自带的ImageView来让它显示圆形图片,具体思路是利用画笔的层叠属性,在图片的底部绘制一个圆形,然后显示上下两层的交集部分,就可以做出一个圆形的ImageView了1.1继承ImageView
[java] view plain copy- 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方法
[java] view plain copy- @Override
- protected 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
[java] view plain copy- 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测试
写好了之后,我们来测试一下 [html] view plain copy- <com.lanou.chenfengyao.temproundimageview.RoundImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@mipmap/test_img"/>
看 图片已经被处理成圆形的了
1.4 添加功能
我们希望可以用我们自己的RoundImageView来实现即可以显示正常的ImageView也可以显示圆形图片的功能,最好可以能用Java代码动态控制.于是我们添加一个自定义属性 首先在values下新建attrs.xml 代码如下 [html] view plain copy- <resources>
- <declare-styleable name="RoundImageView">
- <attr name="is_round" format="boolean" />
- declare-styleable>
- resources>
- private boolean isRound;
- 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);
- }
- @Override
- protected 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);
- }
- }
[java] view plain copy
- "font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">测试一下,我们将我们的组件的is_round属性改成false看看效果
- <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.RoundImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@mipmap/test_img"
- app:is_round="false"/>
- RelativeLayout>
可以看到,现在的RoundImageView就和正常的ImageView的效果是一样的啦. 现在我们再写一个方法能让RoundImgeView动态的改变圆形或是正常的,在RoundImageView里添加方法 [java] view plain copy
- public void setIsRound(boolean isRound) {
- this.isRound = isRound;
- invalidate();
- }
可以看到 我们的图片可以通过Java代码来动态的切换正常模式和圆形图片啦
二、使用Fresco显示圆形图片
Fresco是FaceBook推出的专门用来加载图片的类库,它可以加载网络图片,并且有丰富的效果,并且最重要的是,它具有中文文档! 文档地址http://www.fresco-cn.org/ 根据文档我们首先在gradle里加上 [plain] view plain copy- compile 'com.facebook.fresco:fresco:0.9.0+'
- Fresco.initialize(this);
- <com.facebook.drawee.view.SimpleDraweeView
- fresco: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 [html] view plain copy- <shape
- android: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" />
- <stroke
- android:width="68dp"
- android:color="#FFFFFFFF" />
- shape>
- <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@mipmap/test_img" />
- <item android:drawable="@drawable/circle" />
- layer-list>
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/round_layers"/>
实际上,该方法的原理就是在正常的ImageView上再叠加了一个白色的环形图形,这样显示的效果就是圆形图片了.但是缺点也是显而易见的,即需要手动的调节环形的粗细,比较难控制
更多相关文章
- Android实现图片相似度
- Android绘制(三):Path结合属性动画, 让图标动起来!
- Android(安卓)滑动切换(首页展示,图片、新闻自动切换,循环切换,自动
- 【凯子哥带你学Android】Andriod性能优化之列表卡顿——以“简书
- Android仿搜狗浏览器加载动画
- [置顶] Android中调用系统相机、系统相册来获取图片,并裁剪图片。
- 自定义Android带图片的按钮
- Android多点触控技术实战 针对图片自由缩放和移动
- 摘要:HenCoder Android(安卓)自定义 View 1-8 硬件加速