# kotlin **Repository Path**: zhanpples/kotlin ## Basic Information - **Project Name**: kotlin - **Description**: kotlin - **Primary Language**: Android - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-12-11 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README **本文参考文章 https://github.com/xchengx/ChinaMap https://github.com/jiahuanyu/SVGMapView** **示例图:** ![lamb.gif](https://gitee.com/zhanpples/kotlin/raw/master/gif/lamb.gif) **项目地址 https://gitee.com/zhanpples/kotlin** **数据解析:** ```gradle // dom4j https://mvnrepository.com/artifact/dom4j/dom4j implementation 'dom4j:dom4j:1.6.1' ``` ```kotlin /** * 解析path数据类 */ data class SvgPathData(var path: Path, var fillColor: Int = Color.TRANSPARENT, var strokeColor: Int = Color.TRANSPARENT) ``` ```kotlin class XmlParseTools { companion object { private const val TAG = "XmlParseTools" /** * svg 数据解析 */ fun parseSvg(context: Context, rawRes: Int): List { val saxReader = SAXReader() val rawResource = context.resources.openRawResource(rawRes) val document = saxReader.read(rawResource) val rootElement = document.rootElement Log.e(TAG, "rootElement.name:${rootElement.name}") val listOf = arrayListOf() addPath(rootElement, listOf) val elementsG = rootElement.elements("g") Log.e(TAG, "elements.name:${elementsG.size}") elementsG?.forEach { addPath(it as Element, listOf) } return listOf } /** * 添加path 数据 */ private fun addPath( rootElement: Element, listOf: ArrayList ) { val elements = rootElement.elements("path") Log.e(TAG, "elements.name:${elements.size}") elements.forEach { val element: Element = it as Element val fillColor = element.attribute("fill") val strokeColor = element.attribute("stroke") val pathData = element.attribute("d") val parser = SvgPathHelper().parserSvgPath(pathData.value) val svgPathData = SvgPathData(parser) if (fillColor != null) { svgPathData.fillColor = Color.parseColor(fillColor.value) } if (strokeColor != null) { svgPathData.strokeColor = Color.parseColor(strokeColor.value) } Log.e(TAG, "rootElement.svgPathData:$svgPathData}") listOf.add(svgPathData) } } /** * vector 数据解析 */ fun parseSvgVector(context: Context, rawRes: Int): List { val saxReader = SAXReader() val rawResource = context.resources.openRawResource(rawRes) val document = saxReader.read(rawResource) val rootElement = document.rootElement Log.e(TAG, "rootElement.name:${rootElement.name}") val elements = rootElement.elements("path") val listOf = arrayListOf() elements.forEach { val element: Element = it as Element val fillColor = element.attribute("fillColor") val strokeColor = element.attribute("strokeColor") val pathData = element.attribute("pathData") val parser = SvgPathHelper().parserSvgPath(pathData.value) val svgPathData = SvgPathData(parser) if (fillColor != null) { svgPathData.fillColor = Color.parseColor(fillColor.value) } if (strokeColor != null) { svgPathData.strokeColor = Color.parseColor(strokeColor.value) } listOf.add(svgPathData) } return listOf } } } ``` **绘制path:** ```kotlin //绘制逻辑 override fun onDraw(canvas: Canvas) { super.onDraw(canvas) svgList?.let { svg -> svg.forEach { strokePaint.color = it.strokeColor fillPaint.color = it.fillColor canvas.drawPath(it.path, fillPaint) canvas.drawPath(it.path, strokePaint) } } } ``` **优化:** **根据Path 的computeBounds(RectF bounds, boolean exact)函数可获取path绘制矩形局域,遍历所以path,获取整张svg图的大小,再更具控件大小缩放canvas 实现适配:** ```kotlin { svgList?.let { svg -> val rectF1 = RectF() if (svg.isNotEmpty()) { svg[0].path.computeBounds(rectF, true) svg.forEach { it.path.computeBounds(rectF1, true) if (rectF.left > rectF1.left) { rectF.left = rectF1.left } if (rectF.right < rectF1.right) { rectF.right = rectF1.right } if (rectF.top > rectF1.top) { rectF.top = rectF1.top } if (rectF.bottom < rectF1.bottom) { rectF.bottom = rectF1.bottom } } } //适配View大小 override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) scale = min(measuredWidth / rectF.width(), measuredHeight / rectF.height()) dX = (measuredWidth - scale * rectF.width()) / 2 dY = (measuredHeight - scale * rectF.height()) / 2 Log.e(TAG, "$scale---$dX--$dY") } //绘制逻辑 override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.scale(scale, scale) canvas.translate(dX / scale, dY / scale) //`````` //`````` //`````` } ``` **动画:** **根据PathMeasure测量path长度以及截取指定长度的path实现绘制动画** ```kotlin //存储绘制结束的path private val drawPath = arrayListOf() //path截取长度 private var pathEnd: Float = 0F //截取后的Path private var desPath = Path() /** * 每次绘制跨度 */ var drawStep: Float = 50f /** * 绘制速度单位毫秒 */ var drawSpeedTime: Long = 100L //绘制动画逻辑 private var runnable = object : Runnable { override fun run() { svgList?.let { svg -> if (pathEnd >= pathMeasure.length) { val path = Path() path.lineTo(0F, 0F)//解决绘制bug pathMeasure.getSegment(0F, pathMeasure.length, path, true) drawPath.add(SvgPathData(path, svg[index].fillColor, svg[index].strokeColor)) if (pathMeasure.nextContour()) { pathEnd = 0F } else { index++ if (index > svg.size - 1) { invalidate() postDelayed({ if (isCanAgain) { index = 0 pathEnd = 0F drawPath.clear() pathMeasure.setPath(svg[index].path, true) post(this) } }, againTime) return } pathMeasure.setPath(svg[index].path, true) } } pathEnd += drawStep invalidate() postDelayed(this, drawSpeedTime) } } } //绘制逻辑 override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.scale(scale, scale) canvas.translate(dX / scale, dY / scale) drawPath.forEach { strokePaint.color = Color.RED fillPaint.color = it.fillColor canvas.drawPath(it.path, fillPaint) canvas.drawPath(it.path, strokePaint) } desPath.reset() desPath.lineTo(0F, 0F)//解决绘制bug pathMeasure.getSegment(0F, pathEnd, desPath, true) strokePaint.color = Color.MAGENTA canvas.drawPath(desPath, strokePaint) } } ``` **扩展,基于path触摸事件Region:** ``` public boolean setPath(Path path, Region clip)//将path和clip的两个区域取交集 public boolean contains(int x, int y)//是否包含指定的点(x,y) ``` **项目地址 https://gitee.com/zhanpples/kotlin**