700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android自定义View实现折线统计图

Android自定义View实现折线统计图

时间:2024-05-27 16:29:05

相关推荐

Android自定义View实现折线统计图

最终效果

代码实现

package com.example.chartdemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.DashPathEffect;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathEffect;import android.util.AttributeSet;import android.view.View;import androidx.annotation.Nullable;import java.util.List;public class ChartView extends View {public ChartView(Context context) {this(context,null);}public ChartView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}private int widthMode;private int heightMode;private int widthSize;private int heightSize;private List<Integer> xItems;//X轴 轴项private String xUnit;//X轴 刻度单位private List<Integer> yItems;//Y轴 轴项private String yUnit;//Y轴 刻度单位private List<Integer> dataList;//数据private List<Integer> dataList2;//数据2private int xStepDistance;//X轴 步距private int yStepDistance;//Y轴 步距@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);widthMode = MeasureSpec.getMode(widthMeasureSpec);heightMode = MeasureSpec.getMode(heightMeasureSpec);widthSize = MeasureSpec.getSize(widthMeasureSpec);heightSize = MeasureSpec.getSize(heightMeasureSpec);initPaint();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (xItems==null || xItems.size()==0)return;if (yItems==null || yItems.size()==0)return;//画 X轴=====================================================================================canvas.drawLine(0,heightSize,widthSize, heightSize,zhouPaint);xStepDistance=widthSize/xItems.size();//X轴 步距值for (int a=0;a<xItems.size();a++){//画刻度canvas.drawLine(xStepDistance*a,heightSize,xStepDistance*a, heightSize-10,zhouPaint);//画格子Path gePath=new Path();gePath.moveTo(xStepDistance*a, heightSize);gePath.lineTo(xStepDistance*a, 0);gePath.close();canvas.drawPath(gePath, gePaint);//绘制X轴 刻度文字canvas.drawText(a==xItems.size()-1 ? xItems.get(a)+"("+xUnit+")" : xItems.get(a)+"", xStepDistance*a-10, heightSize-20, textPaint);}canvas.drawLine(widthSize,heightSize,widthSize-10,heightSize-10,zhouPaint);//画末尾箭头//画 Y轴=====================================================================================canvas.drawLine(0,0,0, heightSize,zhouPaint);yStepDistance=heightSize/yItems.size();//Y轴 步距值for (int a=0;a<yItems.size();a++){//画刻度if (a!=0)canvas.drawLine(0,heightSize-(yStepDistance*a),10, heightSize-(yStepDistance*a),zhouPaint);//画格子Path gePath=new Path();gePath.moveTo(0, heightSize-(yStepDistance*a));gePath.lineTo(widthSize, heightSize-(yStepDistance*a));gePath.close();canvas.drawPath(gePath, gePaint);//绘制Y轴 刻度文字canvas.drawText(a==yItems.size()-2 ? yItems.get(a)+"("+yUnit+")" : yItems.get(a)+"", 10, heightSize-(yStepDistance*(a+1)), textPaint);}canvas.drawLine(0,0,10,10,zhouPaint);//画末尾箭头//绘制_数据1===================================================================================double yDataPixel=heightSize/100f; //控件高度的像素个数——与——实际数据的对应关系值 (像素点分给100个数据值)for (int k=0;k<dataList.size();k++){if (k!=dataList.size()-1){canvas.drawLine(xStepDistance*k,(int)(heightSize-(dataList.get(k)*yDataPixel)),xStepDistance*(k+1),(int)(heightSize-(dataList.get(k+1)*yDataPixel)),linePaint);}}//绘制_数据2===================================================================================for (int k=0;k<dataList2.size();k++){if (k!=dataList2.size()-1){canvas.drawLine(xStepDistance*k,(int)(heightSize-(dataList2.get(k)*yDataPixel)),xStepDistance*(k+1),(int)(heightSize-(dataList2.get(k+1)*yDataPixel)), linePaint2);}}}private Paint linePaint;private Paint linePaint2;private Paint zhouPaint;private Paint gePaint;private Paint textPaint;private void initPaint(){linePaint=new Paint();linePaint.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示linePaint.setColor(Color.RED);linePaint.setStrokeWidth(4);linePaint.setAntiAlias(true);//抗锯齿功能linePaint.setARGB(100,255,0,0); //设置:A代表透明度 B代表红 G代表绿 B代表蓝 (范围:0————255)linePaint.setStrokeJoin(Paint.Join.ROUND);//线条连接处样式linePaint.setStrokeCap(Paint.Cap.ROUND);//设置线头模式linePaint2=new Paint();linePaint2.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示linePaint2.setColor(Color.BLUE);linePaint2.setStrokeWidth(4);linePaint2.setAntiAlias(true);//抗锯齿功能linePaint2.setARGB(100,0,0,255);linePaint2.setStrokeJoin(Paint.Join.ROUND);linePaint2.setStrokeCap(Paint.Cap.ROUND);gePaint=new Paint();gePaint.setColor(Color.parseColor("#A3AFB8"));gePaint.setStyle(Paint.Style.STROKE);//不加这个不显示gePaint.setStrokeWidth(0);gePaint.setAntiAlias(true);//抗锯齿功能PathEffect effects = new DashPathEffect(new float[]{5, 10}, 0);//设置绘制虚线gePaint.setPathEffect(effects);zhouPaint=new Paint();zhouPaint.setColor(Color.BLACK);zhouPaint.setStrokeWidth(4);zhouPaint.setAntiAlias(true);//抗锯齿功能textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);textPaint.setTextSize(30);}/*** 设置曲线1 数据* @param dataList*/public void setData(List<Integer> dataList){this.dataList=dataList;postInvalidate();}/*** 设置曲线2 数据* @param dataList*/public void setData2(List<Integer> dataList){this.dataList2=dataList;postInvalidate();}/*** 设置X轴参数* @param xList* @param unit 刻度单位*/public void setDataScaleX(List<Integer> xList,String unit){xItems=xList;xUnit=unit;postInvalidate();}/*** 设置Y轴参数* @param yList* @param unit 刻度单位*/public void setDataScaleY(List<Integer> yList,String unit){yItems=yList;yUnit=unit;postInvalidate();}}

使用方法

第一步:在XML中引用View

<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.chartdemo.ChartViewandroid:id="@+id/chart"android:background="#EFEFEF"android:layout_margin="20px"android:layout_width="match_parent"android:layout_height="600px" /></androidx.constraintlayout.widget.ConstraintLayout>

第二步:设置数据

package com.example.chartdemo;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.widget.ImageView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);List<Integer> dataList=new ArrayList<>();dataList.add(85);dataList.add(90);dataList.add(70);dataList.add(68);dataList.add(50);dataList.add(43);dataList.add(28);dataList.add(21);dataList.add(30);dataList.add(58);dataList.add(70);dataList.add(55);List<Integer> dataList2=new ArrayList<>();dataList2.add(45);dataList2.add(67);dataList2.add(78);dataList2.add(98);dataList2.add(85);dataList2.add(54);dataList2.add(45);dataList2.add(35);dataList2.add(55);dataList2.add(59);dataList2.add(42);dataList2.add(45);List<Integer> xList=new ArrayList<>();xList.add(1);xList.add(2);xList.add(3);xList.add(4);xList.add(5);xList.add(6);xList.add(7);xList.add(8);xList.add(9);xList.add(10);xList.add(11);xList.add(12);List<Integer> yList=new ArrayList<>();yList.add(10);yList.add(20);yList.add(30);yList.add(40);yList.add(50);yList.add(60);yList.add(70);yList.add(80);yList.add(90);yList.add(100);ChartView chart=(ChartView) findViewById(R.id.chart);chart.setDataScaleX(xList,"月");chart.setDataScaleY(yList,"件");chart.setData(dataList);chart.setData2(dataList2);//===========动效数据代码=================doBarChartDataList();}}

动效代码

private void doBarChartDataList(){for (int a=0;a<dataList.size();a++){new BarHeartbeat().start(50, a, dataList.get(a), new ActionCallback() {@Overridepublic void toDo(Object o) {List<Integer> list= (List<Integer>) o;dataList.set(list.get(0),list.get(1));chart.setData(dataList);}});}for (int a=0;a<dataList2.size();a++){new BarHeartbeat().start(50, a, dataList2.get(a), new ActionCallback() {@Overridepublic void toDo(Object o) {List<Integer> list= (List<Integer>) o;dataList2.set(list.get(0),list.get(1));chart.setData2(dataList2);}});}}

动效辅助类

package com.soface.chartdemo;import android.os.Looper;import android.os.Message;import java.util.ArrayList;import java.util.List;/*** 心跳计时器*/public class BarHeartbeat {//事件标签public final int ACTION_TAG =0xFF;//要回调的接口private ActionCallback thisActionDo;//Handler事件监听器private android.os.Handler mHandler = new android.os.Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case ACTION_TAG:List<Integer> list= (List<Integer>) msg.obj;thisActionDo.toDo(list);break;}}};//启动public void start(int countDownTime,int index,int maxNumber,ActionCallback actionDo){thisActionDo=actionDo;for (int a=0;a<=maxNumber;a++){Message msg = mHandler.obtainMessage();msg.what = ACTION_TAG;List<Integer> list=new ArrayList<>();list.add(index);list.add(a);msg.obj=list;mHandler.sendMessageDelayed(msg,countDownTime*a);}};}

package com.soface.chartdemo;public interface ActionCallback {void toDo(Object o);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。