Android SVG

2019-10-10  本文已影响0人  migill

1、SVG概念
SVG是一种图像文件格式,类似于PNG JPG。只不过PNG这种图片需要图像引擎加载,SVG则是由画布来加载,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形。可以让你设计无损失、高分辨率的Web图形界面。用户可以直接用代码来描述图像。

2、SVG在安卓中能做什么

1、App图标:能SDK23后,APP图标都是由SVG来表示
2、自定义控件:不规则的控件,复杂的交互,子控件重叠判断,图标等都可以用SVG来做
3、复杂动画:如根据用户滑动动态显示动画,路径动画

3、SVG语法:

<path/>路径的路径描述指令含义表:
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

4、Region
Region:不规则的连续区域,是绘制中的区域的意思。使用Region可以对图形有很多操作,比如区域的合并,取交集,取抑或等

设置一个连续的矩形区域
public boolean set(Region region)
设置一个path的区域与一个矩形的交集产生的连续性区域
public boolean setPath(Path path, Region clip)
区域中是否包含该坐标
public boolean contains(int x, int y)

使用实例:完成中国地图的绘制,并能正常点击省份。
效果如下图:


public class MapView extends View {
    private int[] colorArray = new int[]{0xFF239BD7, 0xFF30A9E5, 0xFF80CBF1, 0xFFFFFFFF};
    private Context context;
    private List<ProviceItem> itemList;
    private Paint paint;
    private ProviceItem select;
    private RectF totalRect;
    private float scale = 1.0f;//缩放比例

    public MapView(Context context) {
        super(context);
    }

    public MapView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setAntiAlias(true);
        itemList = new ArrayList<>();
        loadThread.start();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取到当前控件宽高值
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (totalRect != null) {
            double mapWidth = totalRect.width();
            scale = (float) (width / mapWidth);//适配手机 计算缩放比
        }

        setMeasuredDimension(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));

    }

    private Thread loadThread = new Thread() {
        @Override
        public void run() {
            final InputStream inputStream = context.getResources().openRawResource(R.raw.china);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  //取得DocumentBuilderFactory实例
            DocumentBuilder builder = null; //从factory获取DocumentBuilder实例
            try {
                builder = factory.newDocumentBuilder();
                Document doc = builder.parse(inputStream);   //解析输入流 得到Document实例
                Element rootElement = doc.getDocumentElement();
                NodeList items = rootElement.getElementsByTagName("path");
                float left = -1;
                float right = -1;
                float top = -1;
                float bottom = -1;
                List<ProviceItem> list = new ArrayList<>();
                for (int i = 0; i < items.getLength(); i++) {
                    Element element = (Element) items.item(i);
                    String pathData = element.getAttribute("android:pathData");
                    @SuppressLint("RestrictedApi") Path path = PathParser.createPathFromPathData(pathData);
                    ProviceItem proviceItem = new ProviceItem(path);
                    proviceItem.setDrawColor(colorArray[i % 4]);
                    RectF rect = new RectF();
                    path.computeBounds(rect, true);
                    left = left == -1 ? rect.left : Math.min(left, rect.left);
                    right = right == -1 ? rect.right : Math.max(right, rect.right);
                    top = top == -1 ? rect.top : Math.min(top, rect.top);
                    bottom = bottom == -1 ? rect.bottom : Math.max(bottom, rect.bottom);
                    list.add(proviceItem);
                }
                itemList = list;
                totalRect = new RectF(left, top, right, bottom);
                //刷新界面
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        requestLayout();
                        invalidate();
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        handleTouch(event.getX() / scale, event.getY() / scale);
        return super.onTouchEvent(event);
    }

    private void handleTouch(float x, float y) {
        if (itemList == null) {
            return;
        }
        ProviceItem selectItem = null;
        for (ProviceItem proviceItem : itemList) {

            if (proviceItem.isTouch(x, y)) {
                selectItem = proviceItem;
            }
        }
        if (selectItem != null) {
            select = selectItem;
            postInvalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (itemList != null) {
            canvas.save();
            canvas.scale(scale, scale);
            for (ProviceItem proviceItem : itemList) {
                if (proviceItem != select) {
                    proviceItem.drawItem(canvas, paint, false);
                } else {
                    select.drawItem(canvas, paint, true);
                }
            }
        }

    }
}

ProviceItem.class是对一个省份的封装,路径和颜色,是否选中,是否点击的判断。

public class ProviceItem {
    private Path path;

    /**
     * 绘制颜色
     */
    private int drawColor;

    public ProviceItem(Path path) {
        this.path = path;
    }

    public void setDrawColor(int drawColor) {
        this.drawColor = drawColor;
    }

    void drawItem(Canvas canvas, Paint paint, boolean isSelect) {
        if (isSelect) {
            //绘制内部的颜色
            paint.clearShadowLayer();
            paint.setStrokeWidth(1);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(drawColor);
            canvas.drawPath(path, paint);
            //绘制边界

            paint.setStyle(Paint.Style.STROKE);
            int strokeColor = 0xFFD0E8F4;
            paint.setColor(strokeColor);
            canvas.drawPath(path, paint);
        } else {

            paint.setStrokeWidth(2);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.FILL);
            paint.setShadowLayer(8, 0, 0, 0xffffff);
            canvas.drawPath(path, paint);

            //绘制边界
            paint.clearShadowLayer();
            paint.setColor(drawColor);
            paint.setStyle(Paint.Style.FILL);
            paint.setStrokeWidth(2);
            canvas.drawPath(path, paint);
        }


    }

    public boolean isTouch(float x, float y) {
        RectF rectF = new RectF();
        path.computeBounds(rectF, true);
        Region region = new Region();

        region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
        return region.contains((int) x, (int) y);
    }
}

svg地图下载地址:
https://www.amcharts.com/download/

上一篇 下一篇

猜你喜欢

热点阅读