1.概述
有时候为了个性、美观,我们需要将一张图片以圆角图片的形式显示,比如想微信等图片很多是圆角矩形,而最新的QQ5.0直接是圆形的,估计考虑到用户看多了再美也庸俗了吧,其实实现这个效果不难,而且一旦了解其中的原理可以按照自己的想法随心所欲的绘制出别出心裁的图片效果来。废话少说,先看一下效果图吧。
2.原理
实现图片圆角等效果使两张图片做一定的集合运算,具体而言是使用了Paint的Xfermode。我们介绍下setXfermode方法,setXfermode方法用来设置两张图片相交时的模式。
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 取两层图像的非交集部门
3.代码实例
1.自定义属性文件:attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundImageView">
<attr name="radius" format="float" />
</declare-styleable>
</resources>
2.实现圆角图片的自定义控件RoundImageView
package com.example.listviewdemo.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.example.listviewdemo.R;
/**
* Description: 自定义的可显示圆角的ImageView
*
* @author danDingCongRong
* @Version 1.0.0
* @Created at 2014-8-11 10:56:38
* @Modified by [作者] on [修改日期]
*/
public class RoundImageView extends ImageView {
private int paddingTop = 0;
private int paddingBottom = 0;
private int paddingLeft = 0;
private int paddingRight = 0;
private float radius = 0.0f;
private float defaultRadius = 0.0f;
public RoundImageView(Context context) {
super(context);
init(context, null);
}
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs,
R.styleable.RoundImageView);
radius = array.getFloat(R.styleable.RoundImageView_radius,
defaultRadius);
// 现在有个问题是:为什么获取的值是实际设置值的1.5倍呢?
paddingTop = getPaddingTop();
paddingBottom = getPaddingBottom();
paddingLeft = getPaddingLeft();
paddingRight = getPaddingRight();
array.recycle();
}
private int measureWidth(int widthMeasureSpec) {
int width = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int spectSize = MeasureSpec.getSize(widthMeasureSpec);
if (MeasureSpec.EXACTLY == specMode) {// match_parent
width = spectSize;
} else {
width = spectSize - paddingLeft - paddingRight;
if (MeasureSpec.AT_MOST == specMode) {// wrap_content
width = Math.min(width, spectSize);
}
}
return width;
}
private int measureHeight(int heightMeasureSpec) {
int height = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if (MeasureSpec.EXACTLY == specMode) {
height = specSize;
} else {
height = specSize - paddingBottom - paddingTop;
if (MeasureSpec.AT_MOST == specMode) {
height = Math.min(height, specSize);
}
}
return height;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec = measureWidth(widthMeasureSpec);
heightMeasureSpec = measureHeight(heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
// 如果调用父类的Draw()将会绘制两张图片
// super.onDraw(canvas);
// 分别获取当前View的宽度和高度
int width = getWidth();
int height = getHeight();
// 获取原始图片资源
Drawable drawable = getDrawable();
Bitmap source = ((BitmapDrawable) drawable).getBitmap();
// 将原始图片变换为圆角图片
Bitmap distance = getRoundConerImage(source);
// 为了让图片资源位于Center,调整图片绘制的位置
int top = (width - distance.getWidth()) / 2;
int left = (height - distance.getHeight()) / 2;
canvas.drawBitmap(distance, top, left, null);
}
protected Bitmap getRoundConerImage(Bitmap source) {
int width = source.getWidth();
int height = source.getHeight();
// 根据指定宽度、高度和图片格式创建Bitmap
Bitmap outputRoundBitmap = Bitmap.createBitmap(width, height,
Config.ARGB_8888);
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
// 使用一个Bitmap初始化一个画布,其密度等特征与Bitmap一致
Canvas canvas = new Canvas(outputRoundBitmap);
canvas.drawARGB(0, 0, 0, 0);
// 初始化要绘制的没有圆角的矩形
Rect rect = new Rect(0, 0, width, height);
RectF rectF = new RectF(rect);
// 绘制一个指定圆角半径的圆角矩形
canvas.drawRoundRect(rectF, radius, radius, paint);
// 设置图片绘制时采用的模式
PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(
Mode.SRC_IN);
paint.setXfermode(porterDuffXfermode);
canvas.drawBitmap(source, 0, 0, paint);
return outputRoundBitmap;
}
}
3.测试代码的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.listviewdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:background="#DEE0E1"
android:orientation="vertical"
android:padding="10dp" >
<com.example.listviewdemo.view.RoundImageView
android:id="@+id/roundImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#8d0000"
android:clickable="true"
android:src="@drawable/ic_launcher" />
<com.example.listviewdemo.view.RoundImageView
android:id="@+id/roundImageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="#8d0000"
android:clickable="true"
android:padding="2dp"
android:src="@drawable/ic_launcher"
app:radius="10" />
<com.example.listviewdemo.view.RoundImageView
android:id="@+id/roundImageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:background="#008d00"
android:clickable="true"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher"
app:radius="30" />
<com.example.listviewdemo.view.RoundImageView
android:id="@+id/roundImageView3"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="20dp"
android:background="#00008d"
android:clickable="true"
android:padding="10dp"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher"
app:radius="45" />
</LinearLayout>
4.测试代码
package com.example.listviewdemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import com.example.listviewdemo.view.RoundImageView;
/**
* Description: 测试圆角图片效果
*
* @author danDingCongRong
* @Version 1.0.0
* @Created at 2014-8-11 14:37:14
* @Modified by [作者] on [修改日期]
*/
public class TestRoundImageViewActivity extends Activity {
private RoundImageView roundImageView;
private RoundImageView roundImageView1;
private RoundImageView roundImageView2;
private RoundImageView roundImageView3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.test_round_imageview_activity);
initView();
}
private void initView() {
roundImageView = (RoundImageView) findViewById(R.id.roundImageView);
roundImageView1 = (RoundImageView) findViewById(R.id.roundImageView1);
roundImageView2 = (RoundImageView) findViewById(R.id.roundImageView2);
roundImageView3 = (RoundImageView) findViewById(R.id.roundImageView3);
roundImageView.setImageResource(R.drawable.test_round_image);
roundImageView1.setImageResource(R.drawable.test_round_image);
roundImageView2.setImageResource(R.drawable.test_round_image);
roundImageView3.setImageResource(R.drawable.test_round_image);
}
}
参考:
1.http://blog.youkuaiyun.com/xyz_lmn/article/details/22745997
2.http://blog.youkuaiyun.com/alan_biao/article/details/17379925
3.http://blog.youkuaiyun.com/lmj623565791/article/details/24555655