我们在Android应用中经常要绘制圆角的图片来展示一些背景图,但是每次都制作圆角的图片很麻烦,而且重复使用率不高。所以我们最好的就是在应用中根据已有的图片,动态的绘制所需要的圆角图片用于显示。话不多说,让我们先看看效果图:

android 圆角边框 安卓圆角矩形图标_canvas

这是例子中使用到的图片:

android 圆角边框 安卓圆角矩形图标_图形_02

怎么样,效果很好吧。

实现绘制圆角图片的原理很简单,就是在程序中动态生成一张Bitmap,然后再用Paint在这张Bitmap中绘制所需的图形(如圆形),再根据paint的setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN))属性设置在Bitmap中画的圆形和所要显示的图片的交集,并取图片部分,那样就生成了圆形的图片。“

其中Mode取值有如下一些值:

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
上下层都显示。



原理就是这样,接下来我们看看示例代码怎么应用:

第一:先看布局文件activity_main.xml

<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" >

    <ImageView
        android:id="@+id/source"
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20dip"
        android:layout_marginTop="20dip"
        android:src="@drawable/demo"/>
    
    <ImageView
        android:id="@+id/circle"
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/source"
        android:layout_marginBottom="20dip"/>
    <ImageView
        android:id="@+id/rect"
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:layout_below="@id/circle"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20dip"/>
    <ImageView
        android:id="@+id/squre"
        android:layout_width="100dip"
        android:layout_height="100dip"
        android:layout_below="@id/rect"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>



这里定义了四个Imageview,第一个为原图,第二个为圆形图片,第三个为圆角矩形,第四个为圆角正方形。


第二:为了节省空间,我就把生成图片的代码写在了MainActivity中,如下,注释都很清楚:

package com.demo.imagetype;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {
	private ImageView circle;
	private ImageView rect;
	private ImageView squre;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        circle = (ImageView)findViewById(R.id.circle);
        rect = (ImageView)findViewById(R.id.rect);
        squre = (ImageView)findViewById(R.id.squre);
        
		/** 获取图片资源并转换为 Bitmap类型 */
        Drawable drawable = getResources().getDrawable(R.drawable.demo); 
		BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;  
		Bitmap bitmap = bitmapDrawable.getBitmap();
        
		circle.setImageBitmap(getCircleBitmap(bitmap));
		rect.setImageBitmap(drawRect(bitmap, 80));
		squre.setImageBitmap(drawSqureRect(bitmap, 80));
    }
    
    
    
    /**
     * 绘制圆形
     * @param source
     * @return
     */
    public static Bitmap getCircleBitmap(Bitmap source)
	{
		// 以最小的边为圆的半径
    	int min = 0;
    	if(source.getWidth() < source.getHeight())
    	{
    		min = source.getWidth();
    	}
    	else
    	{
    		min = source.getHeight();
    	}

		// 获取图片的中心点,使之与圆形的中心点重合,才不会让图片出现偏移
		int x = 0; 
		int y = 0;
		if(source.getWidth() > min)
		{
			x = -(source.getWidth() - min);
		}
		else
		{
			x = min - source.getWidth();
		}
		if(source.getHeight() > min)
		{
			y = -(source.getHeight() - min);
		}
		else
		{
			y = min - source.getHeight();
		}

		// 创建画笔
		final Paint paint = new Paint();
		paint.setAntiAlias(true);
		// 以新建的bitmap创建画布
		Bitmap bitmap = Bitmap.createBitmap(min, min, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		
		// 以图片最小边为直径绘制圆形区域
		canvas.drawCircle(min / 2, min / 2, min / 2, paint);
		
		// 设置圆形区域与要显示的图片相交,并取相交区域的图片为结果图片
		// Mode.SRC_IN:取两层绘制交集。显示上层。
		paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN));
		canvas.drawBitmap(source, x/2, y/2, paint);
		// 返回生成的bitmap,bitmap就是圆形图片
		return bitmap;
	}
    
    /**
     * 绘制圆角矩形
     * @param source
     * @param radius
     * @return
     */
    public Bitmap drawRect(Bitmap source, int radius)
    {
		// 得到要绘制的图片的长和宽,用来绘制圆角矩形的长和宽
    	int width = source.getWidth();
    	int height = source.getHeight();
    	
    	final Paint paint = new Paint();
		paint.setAntiAlias(true);
		
    	Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		
		RectF rect = new RectF(0, 0, width, height);
		canvas.drawRoundRect(rect, radius, radius, paint);
		
		paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN));
		canvas.drawBitmap(source, 0, 0, paint);
		return bitmap;
    }
    
    /**
     * 绘制圆角正方形
     * @param source
     * @param radius
     * @return
     */
    public Bitmap drawSqureRect(Bitmap source, int radius)
    {
    	int min = 0;//获取最小的边长
    	if(source.getWidth() < source.getHeight())
    	{
    		min = source.getWidth();
    	}
    	else
    	{
    		min = source.getHeight();
    	}
    	
    	int x = 0;//绘制中心的x坐标
		int y = 0;//绘制中心的y坐标
		if(source.getWidth() > min)
		{
			x = -(source.getWidth() - min);
		}
		else
		{
			x = min - source.getWidth();
		}
		
		if(source.getHeight() > min)
		{
			y = -(source.getHeight() - min);
		}
		else
		{
			y = min - source.getHeight();
		}
    	
    	final Paint paint = new Paint();
		paint.setAntiAlias(true);
		
    	Bitmap bitmap = Bitmap.createBitmap(min, min, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		RectF rect = new RectF(0, 0, min, min);
		canvas.drawRoundRect(rect, radius, radius, paint);
		paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN));
		canvas.drawBitmap(source, x/2, y/2, paint);//将要绘制的图片中心移动到画布中心
		return bitmap;
    }
}

/**
 * 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
上下层都显示。
**/



其中在绘制圆角矩形的方法中第二个参数就是圆角的弧度,大家可以自己修改试试,看效果如何。好了,虽然代码不多也不复杂,但是确实很实用。