转载请标明出处:http://blog.csdn.NET/joker_ya/article/details/38589677
好吧,写之前扯扯。如果是大神的话,可以忽略此文档。有兴趣的话也可以看看。这是本人的第一篇技术博客吧(话说也谈不上是什么特别的技术)!因为之前在写一个项目需要用到图片。但是把一张图片原封不动的src入ImageView里面去,看起来怪别扭的。因此不想走平民路线,于是就冒出来想把图片弄成三角形的,五角星或圆形的想法。说干就干,所以赶紧上网查了查怎么实现该想法。在此过程中也发现了很多问题,所以今天写出来和大家分享一下。本文是根据大牛鸿洋和alan_biao的博客编写粗来的。原理都和他们的一样,只是在图形上改了改,改成能画出三角形,五角星,心形的形状。大家可以去看看他们得博客,写的都很不错的。鸿洋的博客:http://blog.csdn.net/lmj623565791?viewmode=contents alan_biao的博客:http://blog.csdn.net/alan_biao?viewmode=contents 好吧就扯到这里吧!!写这篇博客的目的一个是为了和大家分享,另一个就是记录自己的收获和成长。
接下来就是如何实现的了。啥也不说了,先上图:
首先是原图:
接下来就是效果图了:
怎么样?是不是比什么都不弄直接src进去的要好呢?根据该方法大家可以实现最新版QQ的消息列表界面:
说了那么多了,还没给你们讲讲是怎么样的一个原理呢!接下来就给大家讲解一下实现该功能的原理:
其实主要是靠画笔paint中的一个方法:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));来实现的。
下面简单的介绍下Xfermode和PorterDuffXfermode:
该Mode是设置两张图片相交时的模式。
在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。如果新的Paint是完全不透明的, 那么它将完全遮挡住下面的Paint;如果它是部分透明的,那么它将会被染上下面的颜色。
而setXfermode就可以来解决这个问题 .
- Canvas canvas = new Canvas(dstBitmap);
- paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- canvas.drawBitmap(srcBitmap, 0f, 0f, paint);
canvas原有的图片可以理解为背景,就是dst;
新画上去的图片可以理解为前景,就是src。
下图可以让大家更好的理解PorterDuffXfermode的Mode:
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
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
取两图层全部区域,交集部分变为透明色
有没有心动了?好了。接下来就是看看如何实现的了。
新建一个名为ShapeViewDemo的项目。目录如下:
在res的文件夹下新建一个名为attrs.xml文件用来定义自定义属性。
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="shapeimageview">
- <attr name="border_size" format="dimension" />
- <attr name="in_border_color" format="color" />
- <attr name="out_border_color" format="color"/>
- <attr name="shape_type" format="string"/>
- </declare-styleable>
- </resources>
接下来新建一个ShapeImageView.Java
- package com.example.shapeimageviewdemo;
-
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.PorterDuff;
- import android.graphics.PorterDuffXfermode;
- import android.graphics.Bitmap.Config;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.Drawable;
- import android.graphics.drawable.NinePatchDrawable;
- import android.util.AttributeSet;
- import android.widget.ImageView;
-
-
-
-
-
-
- public class ShapeImageView extends ImageView {
-
- private Context mContext;
-
- private int border_size = 0;
- private int in_border_color = 0;
- private int out_border_color = 0;
- private int defColor = 0xFFFFFFFF;
-
- private int width = 0;
- private int height = 0;
-
- private String shape_type;
-
- public ShapeImageView(Context context) {
- super(context);
-
- this.mContext = context;
- }
-
- public ShapeImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- this.mContext = context;
- setAttributes(attrs);
- }
-
- public ShapeImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- this.mContext = context;
- setAttributes(attrs);
- }
-
-
-
-
-
-
- private void setAttributes(AttributeSet attrs) {
-
- TypedArray mArray = mContext.obtainStyledAttributes(attrs,
- R.styleable.shapeimageview);
-
- border_size = mArray.getDimensionPixelSize(
- R.styleable.shapeimageview_border_size, 0);
-
- in_border_color = mArray.getColor(
- R.styleable.shapeimageview_in_border_color, defColor);
-
- out_border_color = mArray.getColor(
- R.styleable.shapeimageview_out_border_color, defColor);
-
- shape_type = mArray.getString(R.styleable.shapeimageview_shape_type);
-
- mArray.recycle();
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
-
-
-
- Drawable drawable = getDrawable();
- if (drawable == null) {
- return;
- }
- if (getWidth() == 0 || getHeight() == 0) {
- return;
- }
- this.measure(0, 0);
- if (drawable.getClass() == NinePatchDrawable.class) {
- return;
- }
-
-
- Bitmap mBitmap = ((BitmapDrawable) drawable).getBitmap();
-
- Bitmap cpBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
-
- width = getWidth();
- height = getHeight();
-
- int radius = 0;
-
- if ("round".equals(shape_type)) {
-
- if (in_border_color != defColor && out_border_color != defColor) {
-
- radius = (width < height ? width : height) / 2 - 2
- * border_size;
-
- drawCircleBorder(canvas, radius + border_size / 2,
- in_border_color);
-
- drawCircleBorder(canvas,
- radius + border_size + border_size / 2,
- out_border_color);
- }
- else if (in_border_color != defColor
- && out_border_color == defColor) {
- radius = (width < height ? width : height) / 2 - border_size;
-
- drawCircleBorder(canvas, radius + border_size / 2,
- in_border_color);
- }
- else if (in_border_color == defColor
- && out_border_color != defColor) {
- radius = (width < height ? width : height) / 2 - border_size;
-
- drawCircleBorder(canvas, radius + border_size / 2,
- out_border_color);
- } else {
- radius = (width < height ? width : height) / 2;
- }
- } else {
- radius = (width < height ? width : height) / 2;
- }
-
- Bitmap shapeBitmap = drawShapeBitmap(cpBitmap, radius);
- canvas.drawBitmap(shapeBitmap, width / 2 - radius, height / 2 - radius,
- null);
- }
-
-
-
-
-
-
-
-
- private Bitmap drawShapeBitmap(Bitmap bmp, int radius) {
-
- Bitmap squareBitmap;
- Bitmap scaledBitmap;
- int diameter = radius * 2;
-
- int w = bmp.getWidth();
- int h = bmp.getHeight();
-
- int squarewidth = 0, squareheight = 0;
- int x = 0, y = 0;
- if (h > w) {
- squarewidth = squareheight = w;
- x = 0;
- y = (h - w) / 2;
-
- squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
- squareheight);
- } else if (h < w) {
- squarewidth = squareheight = h;
- x = (w - h) / 2;
- y = 0;
- squareBitmap = Bitmap.createBitmap(bmp, x, y, squarewidth,
- squareheight);
- } else {
- squareBitmap = bmp;
- }
-
- if (squareBitmap.getWidth() != diameter
- || squareBitmap.getHeight() != diameter) {
- scaledBitmap = Bitmap.createScaledBitmap(squareBitmap, diameter,
- diameter, true);
- } else {
- scaledBitmap = squareBitmap;
- }
-
- Bitmap outputbmp = Bitmap.createBitmap(scaledBitmap.getWidth(),
- scaledBitmap.getHeight(), Config.ARGB_8888);
- Canvas canvas = new Canvas(outputbmp);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
- canvas.drawARGB(0, 0, 0, 0);
-
- if ("star".equals(shape_type)) {
- Path path = new Path();
- float radian = degree2Radian(36);
- float radius_in = (float) (radius * Math.sin(radian / 2) / Math
- .cos(radian));
-
- path.moveTo((float) (radius * Math.cos(radian / 2)), 0);
- path.lineTo((float) (radius * Math.cos(radian / 2) + radius_in
- * Math.sin(radian)),
- (float) (radius - radius * Math.sin(radian / 2)));
- path.lineTo((float) (radius * Math.cos(radian / 2) * 2),
- (float) (radius - radius * Math.sin(radian / 2)));
- path.lineTo((float) (radius * Math.cos(radian / 2) + radius_in
- * Math.cos(radian / 2)),
- (float) (radius + radius_in * Math.sin(radian / 2)));
- path.lineTo(
- (float) (radius * Math.cos(radian / 2) + radius
- * Math.sin(radian)), (float) (radius + radius
- * Math.cos(radian)));
- path.lineTo((float) (radius * Math.cos(radian / 2)),
- (float) (radius + radius_in));
- path.lineTo(
- (float) (radius * Math.cos(radian / 2) - radius
- * Math.sin(radian)), (float) (radius + radius
- * Math.cos(radian)));
- path.lineTo((float) (radius * Math.cos(radian / 2) - radius_in
- * Math.cos(radian / 2)),
- (float) (radius + radius_in * Math.sin(radian / 2)));
- path.lineTo(0, (float) (radius - radius * Math.sin(radian / 2)));
- path.lineTo((float) (radius * Math.cos(radian / 2) - radius_in
- * Math.sin(radian)),
- (float) (radius - radius * Math.sin(radian / 2)));
-
- path.close();
- canvas.drawPath(path, paint);
- } else if ("triangle".equals(shape_type)) {
- Path path = new Path();
-
- path.moveTo(0, 0);
- path.lineTo(diameter / 2, diameter);
- path.lineTo(diameter, 0);
-
- path.close();
- canvas.drawPath(path, paint);
- } else if ("heart".equals(shape_type)) {
- Path path = new Path();
-
- path.moveTo(diameter / 2, diameter / 5);
- path.quadTo(diameter, 0, diameter / 2, diameter / 1.0f);
- path.quadTo(0, 0, diameter / 2, diameter / 5);
-
- path.close();
- canvas.drawPath(path, paint);
- } else {
-
- canvas.drawCircle(scaledBitmap.getWidth() / 2,
- scaledBitmap.getHeight() / 2, scaledBitmap.getWidth() / 2,
- paint);
- }
-
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(scaledBitmap, 0, 0, paint);
-
- bmp = null;
- squareBitmap = null;
- scaledBitmap = null;
- return outputbmp;
-
- }
-
-
-
-
-
-
-
- private float degree2Radian(int degree) {
-
- return (float) (Math.PI * degree / 180);
- }
-
-
-
-
-
-
-
-
- private void drawCircleBorder(Canvas canvas, int radius, int color) {
-
- Paint paint = new Paint();
-
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
- paint.setColor(color);
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(border_size);
-
- canvas.drawCircle(width / 2, height / 2, radius, paint);
- }
-
- }
好了
,
ShapeImageView.java写完了,有没有发现其原理很简单呢?在此过程中有一点大家要注意一下,那就是我们重写Ondraw(Canvas canvas)方法时一定要把super.onDraw(canvas);注释掉或去掉,否则会出现两张图片叠在一起。不要问我为什么。
最后附上Activity_main.xml
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:myview="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:orientation="vertical"
- tools:context=".MainActivity" >
-
- <com.example.shapeimageviewdemo.ShapeImageView
- android:layout_width="60dip"
- android:layout_height="60dip"
- android:src="@drawable/girl"
- />
-
- <com.example.shapeimageviewdemo.ShapeImageView
- android:layout_width="80dip"
- android:layout_height="80dip"
- android:layout_marginTop="10dip"
- android:src="@drawable/girl"
- myview:shape_type="triangle"
- />
-
- <com.example.shapeimageviewdemo.ShapeImageView
- android:layout_width="100dip"
- android:layout_height="100dip"
- android:layout_marginTop="10dip"
- android:src="@drawable/girl"
- myview:shape_type="star"
- />
-
- <com.example.shapeimageviewdemo.ShapeImageView
- android:layout_width="100dip"
- android:layout_height="100dip"
- android:layout_marginTop="10dip"
- android:src="@drawable/girl"
- myview:border_size="2dip"
- myview:in_border_color="#EE0000"
- myview:out_border_color="#00EEEE"
- myview:shape_type="round"
- />
-
- <com.example.shapeimageviewdemo.ShapeImageView
- android:layout_width="100dip"
- android:layout_height="100dip"
- android:layout_marginTop="10dip"
- android:src="@drawable/girl"
- myview:shape_type="heart"
- />
- </LinearLayout>
由于用到了自定义属性,因此要在主layout里加上xmlns:myview="http://schemas.android.com/apk/res-auto",否则会报错。
至此,如何将一张图片弄成三角,五角,圆形或心形的图片的全部技术就给大家讲解了。希望对大家有所帮助,也希望大家能理解。当然不仅仅是三角,五角,圆形或心形的形状。只要你想的到的都能弄出来(特殊形状的图片除外),就看你敢不敢了。
由于本人是第一次写博客,如果文中有什么地方出现错误或不理解的可以在下面回复中指出来。谢谢
下面是源码下载地址:
ShapeImageViewDemo