Android 开发自定义使用svg构造交互式中国(各国)地图

自定义开发是android的必不可少的技能之一,要熟练的掌握,需要大家不断的学习,写代码才能日积月累。好了,废话不多说了;看下面的步骤:

1,用的到的两个地址https://www.amcharts.com/svg-maps/?map=china (需要下载国家的svg)

http://inloop.github.io/svg2android/ 下载后需要把svg文件在该地址中解析为Android可识别的代码

2,打开android studio—— res文件下,新建一个raw文件夹,然后把vsg文件复制粘贴到raw文件中,以下图是放入后的效果

3,在java中创建Java类继承View ,实现该类的构成函数,如下代码:

public class ChinaMapView extends View {
    private Paint mPaint;
    private Context context;
    private int[] colors = new int[]{Color.RED, Color.GREEN, Color.YELLOW, Color.GREEN};
    private ArrayList<ProvinceBean> itemList = new ArrayList<>();
    private ProvinceBean selectItem;
    private GestureDetectorCompat gestureDetectorCompat;

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

    private void init(Context context) {
        //准备画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        this.context = context;
        thread.start();

        //手势处理类
        gestureDetectorCompat = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                Log.d("event   ", e.getAction() + "");
                handlerTouch(e.getX(), e.getY());
                return true;
            }
        });

    }

    private void handlerTouch(float x, float y) {
        if (itemList != null) {
            for (ProvinceBean item : itemList) {
                if (item.isTouch((int) (x / 1.4), (int) (y / 1.4))) {
                    selectItem = item;
                    postInvalidate();
                    break;
                }
            }
        }
    }

    public ChinaMapView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetectorCompat.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.scale(1.4f, 1.4f);
        for (int i = 0; i < itemList.size(); i++) {
            if (selectItem != itemList.get(i)) {
                itemList.get(i).draw(mPaint, canvas, false);
            }
        }
        if (selectItem != null) {
            selectItem.draw(mPaint, canvas, true);
        }
        canvas.restore();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg != null) {
                postInvalidate();
            }
        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //dom解析xml
            InputStream inputStream = context.getResources().openRawResource(R.raw.chinahigh);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = null;
            try {
                builder = factory.newDocumentBuilder();
                Document document = builder.parse(inputStream);//解析输入流
                Element rootElement = document.getDocumentElement();
                NodeList items = rootElement.getElementsByTagName("path");
                Log.d("MyMapView:", "集合大小=" + items.getLength());
                for (int i = 0; i < items.getLength(); i++) {
                    int colorsIndex = i % 4;
                    Element element = (Element) items.item(i);
                    String pathData = element.getAttribute("android:pathData");
                    @SuppressLint("RestrictedApi") Path path = PathParser.createPathFromPathData(pathData);
                    ProvinceBean provinceBean = new ProvinceBean(path);
                    provinceBean.setColor(colors[colorsIndex]);
                    itemList.add(provinceBean);
                }
                handler.sendEmptyMessage(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
}

class ProvinceBean {
    private Path path;
    private int color;

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

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    /**
     * 绘制省份
     *
     * @param paint
     * @param canvas
     * @param isSelected 是否被选中
     */
    public void draw(Paint paint, Canvas canvas, boolean isSelected) {
        if (isSelected) {
            //绘制点击后的背景
            paint.setStrokeWidth(2);
            paint.setColor(color);
            paint.setStyle(Paint.Style.FILL);
            //添加阴影
            paint.setShadowLayer(8, 0, 0, Color.BLACK);
            canvas.drawPath(path, paint);
            //绘制背景
            paint.clearShadowLayer();
            paint.setStrokeWidth(2);
            paint.setColor(color);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawPath(path, paint);

        } else {
            //绘制背景
            paint.setStrokeWidth(2);
            paint.clearShadowLayer();
            paint.setColor(color);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawPath(path, paint);
            //绘制边界线
            paint.setStrokeWidth(1);
            paint.setColor(Color.GRAY);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(path, paint);

        }

    }

    //触摸点是否在这个省的path内
    public boolean isTouch(int x, int y) {
        //构造一个矩形对象
        RectF rectF = new RectF();
        //返回路径控制点的计算边界保存到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(x, y);
    }
}

4,在主类中调用该自定义的类:

需要注意的一些坑:

1.2、添加
compile 'com.android.support:appcompat-v7:25.3.1' //需要是23.2 版本以上的

1.3、Activity需要继承与AppCompatActivity

1.4、布局文件当中添加
    xmlns:app="http://schemas.android.com/apk/res-auto"


2、使用在Actvity前面添加一个flag设置
    
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

2.1 ImageView/ImageButton
    XML app:srcCompat
    代码里面使用无区别

2.2 Button 不支持app:srcCompat
    Xml 使用在Button的selector

2.3 RadioButton 直接使用

2.4 textview的drawable  直接使用



2.5 使用的动态Vector Drawable
    主要是不能直接修改 pathData
    不能使用自定义interpolator
发布了16 篇原创文章 · 获赞 3 · 访问量 967

猜你喜欢

转载自blog.csdn.net/chengxuyuan22/article/details/104267875