标签:
原本项目中要实现camu的曝光多边形动画,做好后,产品后来决定不用了。所以源码我就贴出来了。 支持任意多边形 import android.content.Context; import android.graphics.*; import android.graphics.Paint.Style; import android.util.AttributeSet; import android.util.Log; import android.view.View; import java.lang.ref.WeakReference; public class PolygonImageView extends View { private static final String TAG = PolygonImageView.class.getSimpleName(); // 当前UI的宽高 private int mWidth; private int mHeight; // 画笔 private Paint paint; // 绘制目标圆位图画笔 private static int sPolygonColor = Color.BLUE; private WeakReference<Bitmap> mWeakSrcOriBitmap; private WeakReference<Bitmap> mWeakDstOriBitmap; // 多边形默认边宽度 private static float sPolygonWidth = 0f; // 多边形边数 private static int sPolygonNumber = -1; // 多边形内角角度 private static float sPolygonInnerAngel = 180 - (360f / sPolygonNumber); // 多边形内部每一份三角弧形的角度 = 圆周角度 / 多边形边数 private static float sPolygonInnerRadianAngel = 360f / sPolygonNumber; // 多边形内部每一份三角弧形的的间隔,默认2px private static int sPolygonInnerRadianGap = 2; private PorterDuffXfermode mPorterDuffXferMode; private static int sCanvasFlag = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG; public PolygonImageView(Context context) { super(context); } public PolygonImageView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 初始化多边形view的参数 * * @param polygonNumber 多边形的边数 * @param polygonWidth 多边形边宽 * @param polygonColor 多边形颜色 eg:Color.RED * @param polygonGap 多边形内部每一份三角弧形的的间隔,默认2px */ public void initPolygon(int polygonNumber, int polygonWidth, int polygonColor, int polygonGap) { if (polygonNumber < 3) throw new RuntimeException("this [polygonNumber < 3] can't compose to a polygon!"); if (polygonWidth < 0) throw new RuntimeException("this polygonWidth can't be negative!"); if (polygonGap < 0) { Log.i(TAG, "this sPolygonInnerRadianGap can't be negative, will use the default value of 2px"); polygonGap = 2; } sPolygonNumber = polygonNumber; sPolygonWidth = polygonWidth; sPolygonColor = polygonColor; sPolygonInnerRadianGap = polygonGap; sPolygonInnerAngel = 180 - (360f / polygonNumber); sPolygonInnerRadianAngel = 360f / sPolygonNumber; initPaint(); mPorterDuffXferMode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); } private void initPaint() { if (paint == null) { paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.RED); paint.setStyle(Style.FILL); paint.setShader(null); } } /** * 调整多变形的宽度 * * @param widthDelta 宽度的差值 增大为正数,减小为负数 */ public void adjustPolygonWidth(float widthDelta) { sPolygonWidth = sPolygonWidth + widthDelta; if (sPolygonWidth >= mWidth >> 1) { sPolygonWidth = mWidth >> 1; } if (sPolygonWidth <= 0) { sPolygonWidth = 0; } if (mWeakDstOriBitmap != null && mWeakSrcOriBitmap.get() != null) { mWeakDstOriBitmap.clear(); } if (mWeakSrcOriBitmap != null && mWeakSrcOriBitmap.get() != null) { mWeakSrcOriBitmap.clear(); } invalidate(); } // create a bitmap with a circle, used for the "dst" image private Bitmap makeDst(int w, int h) { Bitmap bm; if (mWeakDstOriBitmap != null && mWeakDstOriBitmap.get() != null) { return mWeakDstOriBitmap.get(); } else { bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); } Canvas c = new Canvas(bm); Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dstPaint.setColor(sPolygonColor); float half = w >> 1; Log.i(TAG, "makeDst half = " + half); c.drawCircle(half, half, half, dstPaint); //bitmap缓存起来,避免每次分配内存 mWeakDstOriBitmap = null; mWeakDstOriBitmap = new WeakReference<Bitmap>(bm); return bm; } // create a bitmap with a rect, used for the "src" image private Bitmap makeSrc(int mWidth, int mHeight) { Log.i(TAG, "makeSrc sPolygonWidth = " + sPolygonWidth); Bitmap bm; // 从缓存中获取bitmap,避免每次创建 if (mWeakSrcOriBitmap != null && mWeakSrcOriBitmap.get() != null) { return mWeakSrcOriBitmap.get(); } else { bm = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); } Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(Color.RED); float halfWidth = mWidth >> 1; float halfHeight = mHeight >> 1; // 获取多边形内角三角形的右三角形的底边距离 // 圆心 // /| // / | // / | // / | // /____|____ // |-计算| // |-右边| // |-三角| // |-形这| // |-段的| // |-距离| double polygonRadian = (180 - sPolygonInnerAngel) / 2 * Math.PI / 180; float b = (float) (halfWidth * Math.tan(polygonRadian)); Path path = new Path(); // 移动到多边形内三角形顶点 path.moveTo(halfWidth - sPolygonWidth, halfHeight); // 连接多边形内三角形右下角点 path.lineTo(halfWidth + b - sPolygonWidth, mHeight); // 连接多边形内三角形左下角点 path.lineTo(halfWidth - b - sPolygonWidth, mHeight); // 回连到多边形内三角形顶点 path.lineTo(halfWidth - sPolygonWidth, halfHeight); path.close(); c.drawPath(path, p); //bitmap缓存起来,避免每次分配内存 mWeakSrcOriBitmap = null; mWeakSrcOriBitmap = new WeakReference<Bitmap>(bm); return bm; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (sPolygonNumber == -1) throw new RuntimeException("you must call initPolygon() method first!"); if (mWidth == 0 || mHeight == 0) { mWidth = getWidth(); mHeight = getHeight(); } Bitmap srcB = makeSrc(mWidth, mHeight); Bitmap dstB = makeDst(mWidth, mHeight); // 不能用int,因为有些多边形的角度带有小数点,用int会导致整体角度不准 float degree = 0; for (int i = 0; i < sPolygonNumber; i++) { int sc = canvas.saveLayer(0, 0, mWidth, mHeight, null, sCanvasFlag); // 绘制圆 canvas.drawBitmap(dstB, 0, 0, paint); // 旋转每个三角弧形 canvas.rotate(degree, mWidth >> 1, mHeight >> 1); // 累加下一次旋转的角度 degree = degree + sPolygonInnerRadianAngel; // 设置显示为取两个图形相交的部分 Log.i(TAG, "degree = " + degree); paint.setXfermode(mPorterDuffXferMode); canvas.save(); // 多边形每部分的间隙 canvas.translate(0, sPolygonInnerRadianGap); // 绘制平移间隙后的三角形 canvas.drawBitmap(srcB, 0, 0, paint); canvas.restore(); paint.setXfermode(null); canvas.restoreToCount(sc); } } }
标签:
原文地址:http://blog.csdn.net/android_wql/article/details/45671139