Android怎么绘制双折线图(android,开发技术)

时间:2024-05-05 23:26:31 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

自定义View实现双折线图,可点击,点击后带标签描述,暂未实现拖动的功能,实现效果如下:

Android怎么绘制双折线图

代码如下:

首先,自定义布局属性:

<declare-styleablename="LineChart"><!--type2.LineChart(双折线图)--><attrname="maxYValue"format="integer"/><attrname="yLabelCount"format="integer"/><attrname="xLabelTextSize"format="dimension"/><attrname="xLabelTextColor"format="color"/><attrname="xLabelTextMarginTop"format="dimension"/><attrname="showYLabelText"format="boolean"/><attrname="yLabelTextSize"format="dimension"/><attrname="yLabelTextColor"format="color"/><attrname="yLabelTextMarginLeft"format="dimension"/><attrname="axisWidth"format="dimension"/><attrname="axisColor"format="color"/><attrname="showScale"format="boolean"/><attrname="scaleLength"format="dimension"/><attrname="showGrid"format="boolean"/><attrname="gridWidth"format="dimension"/><attrname="gridDashInterval"format="dimension"/><attrname="gridDashLength"format="dimension"/><attrname="gridColor"format="color"/><attrname="lineWidth"format="dimension"/><attrname="lineColor1"format="color"/><attrname="lineColor2"format="color"/><attrname="labelWidth"format="dimension"/><attrname="labelHeight"format="dimension"/><attrname="labelBackgroundColor"format="color"/><attrname="labelRadius"format="dimension"/><attrname="labelTextSize"format="dimension"/><attrname="labelTextColor"format="color"/><attrname="labelArrowWidth"format="dimension"/><attrname="labelArrowHeight"format="dimension"/><attrname="labelArrowOffset"format="dimension"/><attrname="labelArrowMargin"format="dimension"/><attrname="clickAble"format="boolean"/><attrname="leftMargin"format="dimension"/><attrname="topMargin"format="dimension"/><attrname="rightMargin"format="dimension"/><attrname="bottomMargin"format="dimension"/></declare-styleable>

LineChart的实现如下:

classLineChart@JvmOverloadsconstructor(context:Context,attrs:AttributeSet?=null,@AttrResdefStyleAttr:Int=0):View(context,attrs,defStyleAttr){companionobject{privatevalDEFAULT_MAX_YVALUE=5000privatevalDEFAULT_YLABEL_COUNT=4privatevalDEFAULT_XLABEL_TEXT_SIZE=SizeUtil.sp2px(10f)privatevalDEFAULT_XLABEL_TEXT_COLOR=Color.parseColor("#999999")privatevalDEFAULT_XLABEL_TEXT_MARGIN_TOP=SizeUtil.dp2px(10f)privatevalDEFAULT_SHOW_YLABEL_TEXT=falseprivatevalDEFAULT_YLABEL_TEXT_SIZE=SizeUtil.sp2px(11f)privatevalDEFAULT_YLABEL_TEXT_COLOR=Color.BLACKprivatevalDEFAULT_YLABEL_TEXT_MARGIN_LEFT=SizeUtil.dp2px(15f)privatevalDEFAULT_AXIS_WIDTH=SizeUtil.dp2px(0.5f)privatevalDEFAULT_AXIS_COLOR=Color.parseColor("#F1F1F1")privatevalDEFAULT_SHOW_SCALE=trueprivatevalDEFAULT_SCALE_LENGTH=SizeUtil.dp2px(4f)privatevalDEFAULT_SHOW_GRID=trueprivatevalDEFAULT_GRID_WIDTH=SizeUtil.dp2px(0.5f)privatevalDEFAULT_GRID_DASH_INTERVAL=SizeUtil.dp2px(1f)privatevalDEFAULT_GRID_DASH_LENGTH=SizeUtil.dp2px(2f)privatevalDEFAULT_GRID_COLOR=Color.parseColor("#F1F1F1")privatevalDEFAULT_LINE_WIDTH=SizeUtil.dp2px(1.5f)privatevalDEFAULT_LINE_COLOR1=Color.parseColor("#60BF56")privatevalDEFAULT_LINE_COLOR2=Color.parseColor("#108EE9")privatevalDEFAULT_LABEL_WIDTH=SizeUtil.dp2px(135f)privatevalDEFAULT_LABEL_HEIGHT=SizeUtil.dp2px(78f)privatevalDEFAULT_LABEL_BACKGROUND_COLOR=Color.WHITEprivatevalDEFAULT_LABEL_RADIUS=SizeUtil.dp2px(3f)privatevalDEFAULT_LABEL_TEXT_SIZE=SizeUtil.sp2px(11f)privatevalDEFAULT_LABEL_TEXT_COLOR=Color.parseColor("#333333")privatevalDEFAULT_LABEL_ARROW_WIDTH=SizeUtil.dp2px(8f)privatevalDEFAULT_LABEL_ARROW_HEIGHT=SizeUtil.dp2px(2f)privatevalDEFAULT_LABEL_ARROW_OFFSET=SizeUtil.dp2px(31f)privatevalDEFAULT_LABEL_ARROW_MARGIN=SizeUtil.dp2px(14.5f)privatevalDEFAULT_CLICKABLE=trueprivatevalDEFAULT_LEFT_MARGIN=SizeUtil.dp2px(15f)privatevalDEFAULT_TOP_MARGIN=SizeUtil.dp2px(118f)privatevalDEFAULT_RIGHT_MARGIN=SizeUtil.dp2px(15f)privatevalDEFAULT_BOTTOM_MARGIN=SizeUtil.dp2px(70f)}//Y轴最大值varmaxYValue:Int=DEFAULT_MAX_YVALUE//Y轴上的刻度值个数varyLabelCount:Int=DEFAULT_YLABEL_COUNT//X轴刻度值文本字体大小varxLabelTextSize:Float=DEFAULT_XLABEL_TEXT_SIZE//X轴刻度值文本字体颜色varxLabelTextColor:Int=DEFAULT_XLABEL_TEXT_COLOR//X轴刻度值文本到X轴的上边距varxLabelTextMarginTop:Float=DEFAULT_XLABEL_TEXT_MARGIN_TOP//是否显示Y轴刻度值文本varshowYLabelText:Boolean=DEFAULT_SHOW_YLABEL_TEXT//Y轴刻度值文本字体大小varyLabelTextSize:Float=DEFAULT_YLABEL_TEXT_SIZE//Y轴刻度值文本字体颜色varyLabelTextColor:Int=DEFAULT_YLABEL_TEXT_COLOR//Y轴刻度值文本到屏幕左侧的左边距varyLabelTextMarginLeft:Float=DEFAULT_YLABEL_TEXT_MARGIN_LEFT//X轴宽度varaxisWidth:Float=DEFAULT_AXIS_WIDTH//X轴颜色varaxisColor:Int=DEFAULT_AXIS_COLOR//是否显示轴线上的小刻度线,默认显示varshowScale:Boolean=DEFAULT_SHOW_SCALE//X轴上的小刻度线长度varscaleLength:Float=DEFAULT_SCALE_LENGTH//是否显示网格,默认显示varshowGrid:Boolean=DEFAULT_SHOW_GRID//网格线宽度vargridWidth:Float=DEFAULT_GRID_WIDTH//网格线组成虚线的线段之间的间隔vargridDashInterval:Float=DEFAULT_GRID_DASH_INTERVAL//网格线组成虚线的线段长度vargridDashLength:Float=DEFAULT_GRID_DASH_LENGTH//网格线颜色vargridColor:Int=DEFAULT_GRID_COLOR//折线宽度varlineWidth:Float=DEFAULT_LINE_WIDTH//折线一颜色varlineColor1:Int=DEFAULT_LINE_COLOR1//折线二颜色varlineColor2:Int=DEFAULT_LINE_COLOR2//标签的矩形宽度varlabelWidth:Float=DEFAULT_LABEL_WIDTH//标签的矩形高度varlabelHeight:Float=DEFAULT_LABEL_HEIGHT//标签背景颜色varlabelBackgroundColor=DEFAULT_LABEL_BACKGROUND_COLOR//标签的矩形圆角varlabelRadius:Float=DEFAULT_LABEL_RADIUS//标签内文本字体大小varlabelTextSize:Float=DEFAULT_LABEL_TEXT_SIZE//标签内文本字体颜色varlabelTextColor:Int=DEFAULT_LABEL_TEXT_COLOR//标签的箭头宽度varlabelArrowWidth:Float=DEFAULT_LABEL_ARROW_WIDTH//标签的箭头高度varlabelArrowHeight:Float=DEFAULT_LABEL_ARROW_HEIGHT//标签的箭头到标签左侧或右侧的偏移量varlabelArrowOffset:Float=DEFAULT_LABEL_ARROW_OFFSET//标签的箭头到坐标轴最上方的下边距varlabelArrowMargin:Float=DEFAULT_LABEL_ARROW_MARGIN//是否可点击varclickAble:Boolean=DEFAULT_CLICKABLE//坐标轴到View左侧的边距,多出来的空间可以用来绘制Y轴刻度文本varleftMargin:Float=DEFAULT_LEFT_MARGIN//坐标轴到View顶部的边距,多出来的空间可以用来绘制标签信息vartopMargin:Float=DEFAULT_TOP_MARGIN//坐标轴到View右侧的边距varrightMargin:Float=DEFAULT_RIGHT_MARGIN//坐标轴到View底部的边距,多出来的空间可以用来绘制X轴刻度文本varbottomMargin:Float=DEFAULT_BOTTOM_MARGINprivatevarmCurrentDrawIndex=0privatelateinitvarmAxisPaint:Paint//绘制轴线和轴线上的小刻度线privatelateinitvarmGridPaint:Paint//绘制网格线privatelateinitvarmLinePaint:Paint//绘制折线privatelateinitvarmLabelPaint:Paint//绘制最上方标签privatelateinitvarmLabelBgPaint:Paint//绘制标签背景,带阴影效果privatelateinitvarmTextPaint:Paint//绘制文本privatelateinitvarmLabelRectF:RectF//最上方的标签对应的矩形privatevarmWidth:Int=0privatevarmHeight:Int=0privatevarmXPoint:Float=0f//原点的X坐标privatevarmYPoint:Float=0f//原点的Y坐标privatevarmXScale:Float=0f//X轴刻度长度privatevarmYScale:Float=0f//Y轴刻度长度privatevarmXLength:Float=0f//X轴长度privatevarmYLength:Float=0f//Y轴长度privatevarmClickIndex:Int=0//点击时的下标privatevarmDataList1:MutableList<Float>=mutableListOf()//折线一(交易收益)对应数据privatevarmDataList2:MutableList<Float>=mutableListOf()//折线二(返现收益)对应数据//记录每个数据点的X、Y坐标privatevarmDataPointList1:MutableList<PointF>=mutableListOf()privatevarmDataPointList2:MutableList<PointF>=mutableListOf()privatevarmXLabelList:MutableList<String>=mutableListOf()//X轴刻度值privatevarmYLabelList:MutableList<String>=mutableListOf()//Y轴刻度值init{setLayerType(LAYER_TYPE_SOFTWARE,null)//关闭硬件加速,解决在部分手机无法实现虚线效果attrs?.let{parseAttribute(getContext(),it)}initPaint()setYLable()}//初始化Y轴刻度值privatefunsetYLable(){mYLabelList.clear()valincrement=maxYValue/yLabelCount.toFloat()for(iin0..yLabelCount){vartext=""if(i==0){text="0"}else{valvalue=(increment*i*100).toInt()/100fif(value==value.toInt().toFloat()){text=value.toInt().toString()}else{text=value.toString()}}mYLabelList.add(text)}}//获取布局属性并设置属性默认值privatefunparseAttribute(context:Context,attrs:AttributeSet){valta=context.obtainStyledAttributes(attrs,R.styleable.LineChart)maxYValue=ta.getInt(R.styleable.LineChart_maxYValue,DEFAULT_MAX_YVALUE)yLabelCount=ta.getInt(R.styleable.LineChart_yLabelCount,DEFAULT_YLABEL_COUNT)xLabelTextSize=ta.getDimension(R.styleable.LineChart_xLabelTextSize,DEFAULT_XLABEL_TEXT_SIZE)xLabelTextColor=ta.getColor(R.styleable.LineChart_xLabelTextColor,DEFAULT_XLABEL_TEXT_COLOR)xLabelTextMarginTop=ta.getDimension(R.styleable.LineChart_xLabelTextMarginTop,DEFAULT_XLABEL_TEXT_MARGIN_TOP)showYLabelText=ta.getBoolean(R.styleable.LineChart_showYLabelText,DEFAULT_SHOW_YLABEL_TEXT)yLabelTextSize=ta.getDimension(R.styleable.LineChart_yLabelTextSize,DEFAULT_YLABEL_TEXT_SIZE)yLabelTextColor=ta.getColor(R.styleable.LineChart_yLabelTextColor,DEFAULT_YLABEL_TEXT_COLOR)yLabelTextMarginLeft=ta.getDimension(R.styleable.LineChart_yLabelTextMarginLeft,DEFAULT_YLABEL_TEXT_MARGIN_LEFT)axisWidth=ta.getDimension(R.styleable.LineChart_axisWidth,DEFAULT_AXIS_WIDTH)axisColor=ta.getColor(R.styleable.LineChart_axisColor,DEFAULT_AXIS_COLOR)showScale=ta.getBoolean(R.styleable.LineChart_showScale,DEFAULT_SHOW_SCALE)scaleLength=ta.getDimension(R.styleable.LineChart_scaleLength,DEFAULT_SCALE_LENGTH)showGrid=ta.getBoolean(R.styleable.LineChart_showGrid,DEFAULT_SHOW_GRID)gridWidth=ta.getDimension(R.styleable.LineChart_gridWidth,DEFAULT_GRID_WIDTH)gridDashInterval=ta.getDimension(R.styleable.LineChart_gridDashInterval,DEFAULT_GRID_DASH_INTERVAL)gridDashLength=ta.getDimension(R.styleable.LineChart_gridDashLength,DEFAULT_GRID_DASH_LENGTH)gridColor=ta.getColor(R.styleable.LineChart_gridColor,DEFAULT_GRID_COLOR)lineWidth=ta.getDimension(R.styleable.LineChart_lineWidth,DEFAULT_LINE_WIDTH)lineColor1=ta.getColor(R.styleable.LineChart_lineColor1,DEFAULT_LINE_COLOR1)lineColor2=ta.getColor(R.styleable.LineChart_lineColor2,DEFAULT_LINE_COLOR2)labelWidth=ta.getDimension(R.styleable.LineChart_labelWidth,DEFAULT_LABEL_WIDTH)labelHeight=ta.getDimension(R.styleable.LineChart_labelHeight,DEFAULT_LABEL_HEIGHT)labelBackgroundColor=ta.getColor(R.styleable.LineChart_labelBackgroundColor,DEFAULT_LABEL_BACKGROUND_COLOR)labelRadius=ta.getDimension(R.styleable.LineChart_labelRadius,DEFAULT_LABEL_RADIUS)labelTextSize=ta.getDimension(R.styleable.LineChart_labelTextSize,DEFAULT_LABEL_TEXT_SIZE)labelTextColor=ta.getColor(R.styleable.LineChart_labelTextColor,DEFAULT_LABEL_TEXT_COLOR)labelArrowWidth=ta.getDimension(R.styleable.LineChart_labelArrowWidth,DEFAULT_LABEL_ARROW_WIDTH)labelArrowHeight=ta.getDimension(R.styleable.LineChart_labelArrowHeight,DEFAULT_LABEL_ARROW_HEIGHT)labelArrowOffset=ta.getDimension(R.styleable.LineChart_labelArrowMargin,DEFAULT_LABEL_ARROW_OFFSET)labelArrowMargin=ta.getDimension(R.styleable.LineChart_labelArrowMargin,DEFAULT_LABEL_ARROW_MARGIN)clickAble=ta.getBoolean(R.styleable.LineChart_clickAble,DEFAULT_CLICKABLE)leftMargin=ta.getDimension(R.styleable.LineChart_leftMargin,DEFAULT_LEFT_MARGIN)topMargin=ta.getDimension(R.styleable.LineChart_topMargin,DEFAULT_TOP_MARGIN)rightMargin=ta.getDimension(R.styleable.LineChart_rightMargin,DEFAULT_RIGHT_MARGIN)bottomMargin=ta.getDimension(R.styleable.LineChart_bottomMargin,DEFAULT_BOTTOM_MARGIN)ta.recycle()}//初始化画笔privatefuninitPaint(){mAxisPaint=Paint()with(mAxisPaint){isAntiAlias=truecolor=axisColorstrokeWidth=axisWidth}mGridPaint=Paint()with(mGridPaint){isAntiAlias=truecolor=gridColorstrokeWidth=gridWidthsetPathEffect(DashPathEffect(floatArrayOf(gridDashLength,gridDashInterval),0f))//设置虚线效果}mLinePaint=Paint()with(mLinePaint){isAntiAlias=truestrokeWidth=lineWidthstyle=Paint.Style.STROKE}mLabelPaint=Paint()with(mLabelPaint){isAntiAlias=true}mLabelBgPaint=Paint()with(mLabelBgPaint){isAntiAlias=truecolor=labelBackgroundColor}mTextPaint=Paint()with(mTextPaint){isAntiAlias=truetextAlign=Paint.Align.CENTER}mLabelRectF=RectF()}overridefunonMeasure(widthMeasureSpec:Int,heightMeasureSpec:Int){super.onMeasure(widthMeasureSpec,heightMeasureSpec)valheightMode=MeasureSpec.getMode(heightMeasureSpec)valheightSize=MeasureSpec.getSize(heightMeasureSpec)varheight=0if(heightMode==MeasureSpec.EXACTLY){height=heightSize}else{height=SizeUtil.dp2px(308f).toInt()if(heightMode==MeasureSpec.AT_MOST){height=Math.min(height,heightSize)}}setMeasuredDimension(measuredWidth,height)}overridefunonTouchEvent(event:MotionEvent?):Boolean{valtouchX=event?.getX()?:0ffor(iin0..mDataPointList1.size-1){valcenterX=mDataPointList1[i].xvarbeginX=centerX-mXScale/2fvarendX=centerX+mXScale/2fif(i==0){beginX=0f}if(i==mDataPointList1.size-1){endX=mWidth.toFloat()}if(beginX<touchX&&touchX<endX){mClickIndex=iinvalidate()break}}returntrue}overridefunonDraw(canvas:Canvas?){canvas?.let{initSize(width,height)//初始化尺寸信息drawCoordinate(it)//绘制坐标轴drawLine(it)//绘制折线drawLabel(it)//绘制点击后的效果drawBottomDescription(it)//绘制底部类型说明}}//初始化尺寸信息privatefuninitSize(width:Int,height:Int){mWidth=widthmHeight=heightmXLength=mWidth-leftMargin-rightMarginmYLength=mHeight-topMargin-bottomMarginmXPoint=leftMarginmYPoint=mHeight-bottomMarginmXScale=mXLength/(mXLabelList.size-1)mYScale=mYLength/yLabelCountmDataPointList1.clear()if(hasOnlyOneData()){mDataPointList1.add(PointF(mXPoint+mXLength/2f,calculateYPosition(mDataList1.get(0))))//居中}else{for(iin0..mDataList1.size-1){mDataPointList1.add(PointF(mXPoint+i*mXScale,calculateYPosition(mDataList1.get(i))))}}mDataPointList2.clear()if(hasOnlyOneData()){mDataPointList2.add(PointF(mXPoint+mXLength/2f,calculateYPosition(mDataList2.get(0))))//居中}else{for(iin0..mDataList2.size-1){mDataPointList2.add(PointF(mXPoint+i*mXScale,calculateYPosition(mDataList2.get(i))))}}}//绘制坐标轴privatefundrawCoordinate(canvas:Canvas){//绘制X轴canvas.drawLine(mXPoint-axisWidth/2f,mYPoint,mXPoint+mXLength+axisWidth/2f,mYPoint,mAxisPaint)with(mTextPaint){textSize=xLabelTextSizecolor=xLabelTextColor}valfm=mTextPaint.getFontMetrics()valyOffset=mYPoint+xLabelTextMarginTop-fm.ascentfor(iin0..mXLabelList.size-1){//绘制X轴的刻度值文本if(i==0){//第一个刻度值文本if(hasOnlyOneData()){//只有一条数据时居中显示mTextPaint.textAlign=Paint.Align.CENTERcanvas.drawText(mXLabelList[i],mDataPointList1[i].x,yOffset,mTextPaint)}else{mTextPaint.textAlign=Paint.Align.LEFTcanvas.drawText(mXLabelList[i],mXPoint,yOffset,mTextPaint)}}elseif(i==mXLabelList.size-1){//最后一个刻度值文本mTextPaint.textAlign=Paint.Align.RIGHTcanvas.drawText(mXLabelList[i],mXPoint+mXLength,yOffset,mTextPaint)}else{mTextPaint.textAlign=Paint.Align.CENTERcanvas.drawText(mXLabelList[i],mXPoint+i*mXScale,yOffset,mTextPaint)}//绘制X轴上的小刻度线if(showScale){canvas.drawLine(mXPoint+i*mXScale,mYPoint,mXPoint+i*mXScale,mYPoint-scaleLength,mAxisPaint)}}for(iin0..yLabelCount-1){//绘制网格线:横刻线if(showGrid){mGridPaint.color=gridColorcanvas.drawLine(mXPoint,mYPoint-(i+1)*mYScale,mXPoint+mXLength,mYPoint-(i+1)*mYScale,mGridPaint)}//绘制Y轴上的刻度值if(showYLabelText){with(mTextPaint){textSize=yLabelTextSizecolor=yLabelTextColortextAlign=Paint.Align.LEFT}if(i==0){canvas.drawText(mYLabelList[i],yLabelTextMarginLeft,mYPoint,mTextPaint)}valyLabelFm=mTextPaint.getFontMetrics()valyLabelYOffset=mYPoint+(yLabelFm.descent-yLabelFm.ascent)/2f-yLabelFm.descent-(i+1)*mYScalecanvas.drawText(mYLabelList[i+1],yLabelTextMarginLeft,yLabelYOffset,mTextPaint)}}}//绘制折线privatefundrawLine(canvas:Canvas){if(mDataList1==null||mDataList1.size<=0||mDataList2==null||mDataList2.size<=0){return}if(hasOnlyOneData()){//处理只有一条数据的情况//绘制第一条直线mLinePaint.color=lineColor1canvas.drawLine(mXPoint,mDataPointList1[0].y,mXPoint+mXLength,mDataPointList1[0].y,mLinePaint)//绘制第二条直线mLinePaint.color=lineColor2canvas.drawLine(mXPoint,mDataPointList2[0].y,mXPoint+mXLength,mDataPointList2[0].y,mLinePaint)return}for(iin0..mDataPointList1.size-2){if(i<=mCurrentDrawIndex){//绘制第一条折线//绘制折线mLinePaint.color=lineColor1canvas.drawLine(mDataPointList1[i].x,mDataPointList1[i].y,mDataPointList1[i+1].x,mDataPointList1[i+1].y,mLinePaint)//绘制折线交点canvas.drawCircle(mDataPointList1[i].x,mDataPointList1[i].y,lineWidth*1.5f,mLinePaint)mLinePaint.color=Color.WHITEcanvas.drawCircle(mDataPointList1[i].x,mDataPointList1[i].y,lineWidth*0.5f,mLinePaint)//绘制第二条折线//绘制折线mLinePaint.color=lineColor2canvas.drawLine(mDataPointList2[i].x,mDataPointList2[i].y,mDataPointList2[i+1].x,mDataPointList2[i+1].y,mLinePaint)//绘制折线交点canvas.drawCircle(mDataPointList2[i].x,mDataPointList2[i].y,lineWidth*1.5f,mLinePaint)mLinePaint.color=Color.WHITEcanvas.drawCircle(mDataPointList2[i].x,mDataPointList2[i].y,lineWidth*0.5f,mLinePaint)//绘制最后一个折线交点if(i==mDataPointList1.size-2){mLinePaint.color=lineColor1canvas.drawCircle(mDataPointList1[mDataPointList1.size-1].x,mDataPointList1[mDataPointList1.size-1].y,lineWidth*1.5f,mLinePaint)mLinePaint.color=Color.WHITEcanvas.drawCircle(mDataPointList1[mDataPointList1.size-1].x,mDataPointList1[mDataPointList1.size-1].y,lineWidth*0.5f,mLinePaint)mLinePaint.color=lineColor2canvas.drawCircle(mDataPointList2[mDataPointList2.size-1].x,mDataPointList2[mDataPointList2.size-1].y,lineWidth*1.5f,mLinePaint)mLinePaint.color=Color.WHITEcanvas.drawCircle(mDataPointList2[mDataPointList2.size-1].x,mDataPointList2[mDataPointList2.size-1].y,lineWidth*0.5f,mLinePaint)}}}}//计算数值对应的Y坐标privatefuncalculateYPosition(data:Float):Float=mYPoint-data/maxYValue*mYLength//绘制点击后的详情展示privatefundrawLabel(canvas:Canvas){if(clickAble&&mDataList1.size>0){//绘制点击后的竖刻线mLabelPaint.color=Color.parseColor("#EBEBEB")mLabelPaint.strokeWidth=DEFAULT_GRID_WIDTH*2canvas.drawLine(mDataPointList1[mClickIndex].x,mYPoint,mDataPointList1[mClickIndex].x,topMargin-labelArrowMargin,mLabelPaint)//绘制点击后的折线交点mLabelPaint.color=lineColor1canvas.drawCircle(mDataPointList1[mClickIndex].x,mDataPointList1[mClickIndex].y,lineWidth*2.3f,mLabelPaint)mLabelPaint.color=lineColor2canvas.drawCircle(mDataPointList2[mClickIndex].x,mDataPointList2[mClickIndex].y,lineWidth*2.3f,mLabelPaint)//绘制最上方标签信息with(mLabelRectF){bottom=topMargin-labelArrowMargin-labelArrowHeighttop=bottom-labelHeight;left=mDataPointList1[mClickIndex].x-labelArrowWidth/2f-labelArrowOffsetright=left+labelWidth//处理点击第一项出现标签偏离整个折线图现象if(left<0){left=SizeUtil.dp2px(5f)right=left+labelWidth}//处理点击最后一项出现标签偏离整个折线图现象if(right>mWidth){right=mWidth.toFloat()-SizeUtil.dp2px(5f)left=right-labelWidth}}//绘制圆角矩形mLabelBgPaint.setShadowLayer(SizeUtil.dp2px(12f),//阴影效果SizeUtil.dp2px(2.5f),SizeUtil.dp2px(1.5f),Color.parseColor("#C7C7C7"))canvas.drawRoundRect(mLabelRectF,labelRadius,labelRadius,mLabelBgPaint)//绘制箭头valarrowPath=Path()with(arrowPath){moveTo(mDataPointList1[mClickIndex].x,topMargin-labelArrowMargin)valbaseY=topMargin-labelArrowMargin-labelArrowHeight-SizeUtil.dp2px(1f)lineTo(mDataPointList1[mClickIndex].x-labelArrowWidth/2f,baseY)lineTo(mDataPointList1[mClickIndex].x+labelArrowWidth/2f,baseY)close()}mLabelPaint.color=labelBackgroundColorcanvas.drawPath(arrowPath,mLabelPaint)mLabelPaint.color=Color.parseColor("#F1F1F1")mLabelPaint.strokeWidth=gridWidthcanvas.drawLine(mLabelRectF.left+SizeUtil.dp2px(10f),mLabelRectF.bottom-SizeUtil.dp2px(52f),mLabelRectF.right-SizeUtil.dp2px(10f),mLabelRectF.bottom-SizeUtil.dp2px(52f),mLabelPaint)//绘制文字with(mTextPaint){color=labelTextColortextSize=labelTextSizetextAlign=Paint.Align.LEFT}canvas.drawText(mXLabelList[mClickIndex],mLabelRectF.left+SizeUtil.dp2px(9.5f),mLabelRectF.bottom-SizeUtil.dp2px(61f),mTextPaint)canvas.drawText("交易收益¥${mDataList1[mClickIndex]}",mLabelRectF.left+SizeUtil.dp2px(19.5f),mLabelRectF.bottom-SizeUtil.dp2px(32.5f),mTextPaint)canvas.drawText("返现收益¥${mDataList2[mClickIndex]}",mLabelRectF.left+SizeUtil.dp2px(19.5f),mLabelRectF.bottom-SizeUtil.dp2px(12.5f),mTextPaint)mTextPaint.color=lineColor1canvas.drawCircle(mLabelRectF.left+SizeUtil.dp2px(12.5f),mLabelRectF.bottom-SizeUtil.dp2px(36f),SizeUtil.dp2px(2.5f),mTextPaint)mTextPaint.color=lineColor2canvas.drawCircle(mLabelRectF.left+SizeUtil.dp2px(12.5f),mLabelRectF.bottom-SizeUtil.dp2px(16f),SizeUtil.dp2px(2.5f),mTextPaint)}}//绘制底部类型说明privatefundrawBottomDescription(canvas:Canvas){if(mDataList1==null||mDataList1.size==0||mDataList2==null||mDataList2.size==0){return}mTextPaint.color=lineColor1valcenterX1=mWidth/2f-SizeUtil.dp2px(75.5f)canvas.drawCircle(centerX1,mHeight-SizeUtil.dp2px(20f),SizeUtil.dp2px(3.5f),mTextPaint)mTextPaint.color=lineColor2valcenterX2=mWidth/2f+SizeUtil.dp2px(16f)canvas.drawCircle(centerX2,mHeight-SizeUtil.dp2px(20f),SizeUtil.dp2px(3.5f),mTextPaint)mTextPaint.color=Color.WHITEcanvas.drawCircle(centerX1,mHeight-SizeUtil.dp2px(20f),SizeUtil.dp2px(2.2f),mTextPaint)canvas.drawCircle(centerX2,mHeight-SizeUtil.dp2px(20f),SizeUtil.dp2px(2.2f),mTextPaint)with(mTextPaint){color=labelTextColortextSize=SizeUtil.sp2px(12f)}canvas.drawText("交易收益",centerX1+SizeUtil.dp2px(8f),mHeight-SizeUtil.dp2px(15.5f),mTextPaint)canvas.drawText("返现收益",centerX2+SizeUtil.dp2px(8f),mHeight-SizeUtil.dp2px(15.5f),mTextPaint)}//格式化标签内的数值文本privatefunformatValue(value:Float):String{valscale=maxYValue/yLabelCount.toFloat()if(scale<10&&(value!=value.toInt().toFloat())&&(value>=0.01f)){return"${(value*100).toInt().toFloat()/100}"//保留2位小数,但不四舍五入}return"${value.toInt()}"}//是否只有一条数据privatefunhasOnlyOneData():Boolean=mDataList1.size==1&&mDataList2.size==1&&mXLabelList.size==1//设置数据,startAnim:是否开启动画,动画默认一条一条折线的画//list1和list2的数据个数要相同,dateList的数据个数大于等于list1和list2的数据个数fundrawData(list1:MutableList<Float>,list2:MutableList<Float>,dateList:MutableList<String>,startAnim:Boolean=false){if(list1.size!=list2.size){throwRuntimeException("thesizeoflist1mustbeequaltothesizeoflist2")}if(dateList.size<list1.size){throwRuntimeException("thesizeofdateListcannotlessthanthesizeoflist1")}varmaxValue=0ffor(iteminlist1){if(maxValue<=item){maxValue=item}}for(iteminlist2){if(maxValue<=item){maxValue=item}}mDataList1=list1mDataList2=list2mXLabelList=dateListmaxYValue=calculateMaxValue(maxValue)mClickIndex=0setYLable()//重新设置Y轴刻度值if(startAnim){valanimator=ValueAnimator.ofInt(0,mDataList1.size-2)animator.setDuration(1500)animator.addUpdateListener{mCurrentDrawIndex=it.getAnimatedValue()asIntinvalidate()}animator.interpolator=LinearInterpolator()animator.start()}else{mCurrentDrawIndex=mDataList1.size-2invalidate()}}//计算Y轴最大值和单位,计算规则:最高位数加1取整privatefuncalculateMaxValue(value:Float):Int{valvalueStr=value.toLong().toString()vallength=valueStr.length//整数的位数valunit=Math.pow(10.0,(length-1).toDouble()).toInt()if(value==0f){returnDEFAULT_MAX_YVALUE//如果最大值是0,即所有数据都是0,取默认的最大值}elseif(value%unit==0f){returnvalue.toInt()}else{return((value/unit).toInt()+1)*unit}}}

使用举例:

privatefuncreateType2Data(count:Int,isDateMore:Boolean=false,startAnim:Boolean=false,showYLabelText:Boolean=false){vallist1:MutableList<Float>=mutableListOf()vallist2:MutableList<Float>=mutableListOf()valdateList:MutableList<String>=mutableListOf()for(iin0..count){list1.add(Random.nextDouble(80.0).toFloat())list2.add(Random.nextDouble(80.0).toFloat())dateList.add(DateUtil.getDistanceDateByDay(i-count,DateUtil.M_D))}if(isDateMore){dateList.add(DateUtil.getDistanceDateByDay(1,DateUtil.M_D))}if(showYLabelText){binding.type2Lc.leftMargin=SizeUtil.dp2px(40f)}else{binding.type2Lc.leftMargin=SizeUtil.dp2px(15f)}binding.type2Lc.showYLabelText=showYLabelTextbinding.type2Lc.drawData(list1,list2,dateList,startAnim)}
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Android怎么绘制双折线图的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:Linux中的mail命令怎么用下一篇:

10 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18