package com.moonlight.example;
import com.larvalabs.svgandroid.SVG;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* @ClassName: SVGView
* @Description: Scalable Vector Graphics M = moveto 相当于 android Path 里的moveTo(),用于移动起始点 L = lineto
* 相当于 android Path 里的lineTo(),用于画线 H = horizontal lineto 用于画水平线 V = vertical lineto
* 用于画竖直线 C = curveto 相当于cubicTo(),三次贝塞尔曲线 S = smooth curveto 同样三次贝塞尔曲线,更平滑 Q =
* quadratic Belzier curve quadTo(),二次贝塞尔曲线 T = smooth quadratic Belzier curveto
* 同样二次贝塞尔曲线,更平滑 A = elliptical Arc 相当于arcTo(),用于画弧 Z = closepath 相当于closeTo(),关闭path
* @author: moonlight
* @date: 2016-9-19 下午4:06:15
*/
public class SVGView extends View {
public static final String TAG = "SVGView";
private Drawable sp_close, sp_scale, sp_flip;
private RectF dstRect;
private Paint paint_region;
private TouchHelper touchHelper;
private SVG svg;
private Bitmap svgBitmap;
private RectF srcRect;
private float[] srcPts = new float[8];
private float[] dstPts = new float[8];
//用于svg的bitmap做旋转
private Matrix svgMatrix = new Matrix();
private Matrix rectMatrix = new Matrix();
private ISVGAction svgAction;
private float degreeTotal, flip = 1f;
float[] values = new float[9];
public SVGView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SVGView(Context context) {
super(context);
init(context);
}
public void init(Context context) {
sp_close = getResources().getDrawable(R.drawable.sp_close);
sp_scale = getResources().getDrawable(R.drawable.sp_scale);
sp_flip = getResources().getDrawable(R.drawable.sp_flip);
dstRect = new RectF();
srcRect = new RectF();
paint_region = new Paint();
paint_region.setColor(Color.BLACK);
paint_region.setStyle(Style.STROKE);
touchHelper = new TouchHelper();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (svg != null && svgBitmap == null) {
int svg_w = svg.getPicture().getWidth();
int svg_h = svg.getPicture().getHeight();
int w_valid = w - sp_close.getIntrinsicWidth();
int h_valid = h - sp_close.getIntrinsicHeight();
if (svg_w > (w_valid) || svg_h > (h_valid)) {
float scale_w = 1.0f * svg_w / w_valid;
float scale_h = 1.0f * svg_h / h_valid;
float scale = Math.max(scale_w, scale_h);
svg_w /= scale;
svg_h /= scale;
}
srcRect = new RectF(0, 0, svg_w, svg_h);
srcPts[0] = srcRect.left;
srcPts[1] = srcRect.top;
srcPts[2] = srcRect.right;
srcPts[3] = srcRect.top;
srcPts[4] = srcRect.right;
srcPts[5] = srcRect.bottom;
srcPts[6] = srcRect.left;
srcPts[7] = srcRect.bottom;
rectMatrix.postTranslate(w / 2f - srcRect.centerX(), h / 2f - srcRect.centerY());
touchHelper.lastDegree = (float) Math.toDegrees(Math.atan2(svg_h, svg_w));
rectMatrix.mapRect(dstRect, srcRect);
rectMatrix.mapPoints(dstPts, srcPts);
changeSVGBitmap();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return touchHelper.onTouchEvent(event);
}
public void setSVG(SVG svg) {
this.svg = svg;
//可能View还没有初始化
if (getWidth() != 0 && getHeight() != 0) {
changeSVGBitmap();
}
}
public enum RegionAction {
MOVE, CLOSE, FINISH, SCALE, FLIP, NONE;
}
public RegionAction judgeRegionAction(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
//先判断四个控制点在判断移动区域
if (sp_scale.getBounds().contains(x, y)) {
return RegionAction.SCALE;
}
if (sp_close.getBounds().contains(x, y)) {
return RegionAction.CLOSE;
}
if (sp_flip.getBounds().contains(x, y)) {
return RegionAction.FLIP;
}
Matrix inverse = new Matrix();
rectMatrix.invert(inverse);
float[] pt = new float[] { x, y };
inverse.mapPoints(pt);
if (srcRect.contains(pt[0], pt[1])) {
return RegionAction.MOVE;
}
return RegionAction.FINISH;
}
public class TouchHelper {
private float lastX, lastY;
private RegionAction actionRegion;
private float lastDegree;
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
lastY = event.getY();
actionRegion = judgeRegionAction(event);
break;
case MotionEvent.ACTION_MOVE: {
switch (actionRegion) {
case MOVE: {
float dx = (event.getX() - lastX);
float dy = (event.getY() - lastY);
regionMove(dx, dy);
lastX = event.getX();
lastY = event.getY();
invalidate();
break;
}
case SCALE: {
regionScale(event);
regionRotate(event);
changeSVGBitmap();
lastX = event.getX();
lastY = event.getY();
invalidate();
break;
}
default:
break;
}
}
break;
case MotionEvent.ACTION_UP:
RegionAction actionRegionDown = judgeRegionAction(event);
actionRegion = actionRegionDown == actionRegion ? actionRegionDown : RegionAction.NONE;
switch (actionRegion) {
case CLOSE:
closeAction();
break;
case FINISH:
finishAction();
break;
case FLIP:
flipAction();
invalidate();
break;
default:
break;
}
break;
default:
break;
}
return true;
}
public void regionMove(float dx, float dy) {
//if (dx < 0 && dstRect.left + dx < 0) {
// dx = -dstRect.left;
//} else if (dx > 0 && dstRect.right + dx > getWidth()) {
// dx = getWidth() - (dstRect.right);
//}
//if (dy < 0 && dstRect.top + dy < 0) {
// dy = -dstRect.top;
//} else if (dy > 0 && dstRect.bottom + dy > getHeight()) {
// dy = getHeight() - (dstRect.bottom);
//}
rectMatrix.postTranslate(dx, dy);
}
public void regionRotate(MotionEvent event) {
float degree = (float) Math.toDegrees(Math.atan2(event.getY() - dstRect.centerY(),
event.getX() - dstRect.centerX()));
float degreeChange = degree - lastDegree;
degreeTotal = (degreeTotal + degreeChange) % 360;
rectMatrix.postRotate(degreeChange, dstRect.centerX(), dstRect.centerY());
lastDegree = degree;
}
//基于中心点放缩
public void regionScale(MotionEvent event) {
float centerX = dstRect.centerX();
float centerY = dstRect.centerY();
float scale = (float) (Math.sqrt((event.getY() - centerY) * ((event.getY() - centerY))
+ (event.getX() - centerX) * (event.getX() - centerX)) / Math.sqrt((lastY - centerY)
* ((lastY - centerY)) + (lastX - centerX) * (lastX - centerX)));
rectMatrix.postScale(scale, scale, centerX, centerY);
svgMatrix.postScale(scale, scale);
}
public void finishAction() {
if (svgAction != null) {
svgAction.done(svgBitmap, new Rect((int) dstRect.left, (int) dstRect.top, (int) dstRect.right,
(int) dstRect.bottom));
}
}
public void closeAction() {
if (svgAction != null) {
svgAction.close();
}
}
private void flipAction() {
flip *= -1;
//这个会变换坐标系,将x的方向翻转
changeSVGBitmap();
}
}
public void setSVGAction(ISVGAction action) {
this.svgAction = action;
}
public interface ISVGAction {
public void close();
public void done(Bitmap bitmap, Rect postion);
}
//思路:先绘制未旋转的bmp,在去中心点做旋转操作
public void changeSVGBitmap() {
//变换前获得最终效果dstRect
rectMatrix.mapRect(dstRect, srcRect);
RectF svgRect, svgNoRotateRect;
svgRect = new RectF(0, 0, (int) dstRect.width(), (int) dstRect.height());
svgNoRotateRect = new RectF();
svgMatrix.mapRect(svgNoRotateRect, srcRect);
if (svgBitmap == null || (svgBitmap.getWidth() != svgRect.width() || svgBitmap.getHeight() != svgRect.height())) {
if (svgBitmap != null)
svgBitmap.recycle();
svgBitmap = Bitmap.createBitmap((int) svgRect.width(), (int) svgRect.height(), Config.ARGB_4444);
}
//对canvas先做旋转,翻转,再做位移,注意顺序:位移最后做
Canvas c = new Canvas(svgBitmap);
c.drawColor(Color.TRANSPARENT, Mode.CLEAR);
c.rotate(degreeTotal, svgRect.centerX(), svgRect.centerY());
c.scale(flip, 1, svgRect.centerX(), svgRect.centerY());
c.translate((svgRect.width() - svgNoRotateRect.width()) / 2f, (svgRect.height() - svgNoRotateRect.height()) / 2);
//对svgNoRotateRect只做位移变换
//Matrix m = new Matrix();
//m.postTranslate((svgRect.width() - svgNoRotateRect.width()) / 2f, (svgRect.height() - svgNoRotateRect.height()) / 2);
//m.mapRect(svgNoRotateRect);
c.drawPicture(svg.getPicture(), svgNoRotateRect);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (svgBitmap != null) {
rectMatrix.mapRect(dstRect, srcRect);
rectMatrix.mapPoints(dstPts, srcPts);
drawFrame(canvas);
canvas.drawBitmap(svgBitmap, dstRect.centerX() - svgBitmap.getWidth() / 2f,
dstRect.centerY() - svgBitmap.getHeight() / 2f, null);
drawControlBtns(canvas);
}
}
private void drawControlBtns(Canvas canvas) {
setBoundsByCenterXY(sp_close, dstPts[0], dstPts[1]);
sp_close.draw(canvas);
setBoundsByCenterXY(sp_flip, dstPts[2], dstPts[3]);
sp_flip.draw(canvas);
setBoundsByCenterXY(sp_scale, dstPts[4], dstPts[5]);
sp_scale.draw(canvas);
}
private void drawFrame(Canvas canvas) {
canvas.drawLine(dstPts[0], dstPts[1], dstPts[2], dstPts[3], paint_region);
canvas.drawLine(dstPts[2], dstPts[3], dstPts[4], dstPts[5], paint_region);
canvas.drawLine(dstPts[4], dstPts[5], dstPts[6], dstPts[7], paint_region);
canvas.drawLine(dstPts[6], dstPts[7], dstPts[0], dstPts[1], paint_region);
}
private void setBoundsByCenterXY(Drawable drawable, float centerX, float centerY) {
drawable.setBounds((int) centerX - drawable.getIntrinsicWidth() / 2,
(int) centerY - drawable.getIntrinsicHeight() / 2, (int) centerX + drawable.getIntrinsicWidth() / 2,
(int) centerY + drawable.getIntrinsicHeight() / 2);
}
}