我们在Android应用中经常要绘制圆角的图片来展示一些背景图,但是每次都制作圆角的图片很麻烦,而且重复使用率不高。所以我们最好的就是在应用中根据已有的图片,动态的绘制所需要的圆角图片用于显示。话不多说,让我们先看看效果图:
这是例子中使用到的图片:
怎么样,效果很好吧。
实现绘制圆角图片的原理很简单,就是在程序中动态生成一张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
上下层都显示。
**/
其中在绘制圆角矩形的方法中第二个参数就是圆角的弧度,大家可以自己修改试试,看效果如何。好了,虽然代码不多也不复杂,但是确实很实用。