安卓自定义View实现简单折线图
来源:互联网 发布:自学编程应该看什么书 编辑:程序博客网 时间:2024/05/17 04:10
自定义View实现折线图:
运行效果:
少说废话,实现起来还是比较简单的,无非就是使用canvas进行绘图,以及坐标的计算,下面直接贴代码:
ChartView.java
/** * Created by wangke on 2017/2/20. * 自定义折线图 */public class ChartView extends View{ private int mViewHeight; //当前View的高 private int mViewWidth; //当前View的宽 private Paint mPaintCdt;// 绘制坐标系的画笔 private Paint mPaintSysPoint; //绘制坐标系上刻度点 private Paint mPaintLinePoint; //绘制折线上的点 private Paint mPaintText; //绘制文字 private Paint mPaintLine; //绘制折线 private Paint mPaintDash; //绘制虚线 private Paint mPaintSys; //x,y轴 private Rect mXBound; private Rect mYBound; private ArrayList<Point> pointList = null; private int X_MAX; //传入点的X的最大坐标 private int Y_MAX; //传入点的Y的最大坐标 private float mScreenXdistance; //x轴刻度在屏幕上的间隔 private float mScreenYdistance; //y轴刻度在屏幕上的间隔 //折线图距离四周的像素大小 private int Margin = 80; private int coordinateSystemColor; private float coordinateSystemSize; private int lineColor; private float lineSize; private int lineColorPoint; private float lineColorPointRadius; private int scalePointColor; private float scalePointRadius; private boolean isShowDash; private int xScale; private int yScale; private float dashSize; private int dashColor; public ChartView(Context context) { super(context); InitPaint(); } //设置点的数据 public void setPoint(ArrayList<Point> points) { pointList = new ArrayList(); pointList = points; int []xPointArray = new int[100]; int []yPointArray = new int[100]; //遍历传入的点的坐标,获取最大的x,y点的坐标,用来计算刻度 for(int i=0;i<pointList.size();i++){ Point point = pointList.get(i); xPointArray[i] = point.x; yPointArray[i] = point.y; } Arrays.sort(xPointArray); Arrays.sort(yPointArray); X_MAX = xPointArray[xPointArray.length-1]; Y_MAX = yPointArray[yPointArray.length-1]; Log.i("wk","X的最大坐标:"+xPointArray[xPointArray.length-1]); Log.i("wk","y的最大坐标:"+yPointArray[yPointArray.length-1]); //调用绘制 invalidate(); } //初始化画笔 private void InitPaint() { mPaintCdt = new Paint(Paint.ANTI_ALIAS_FLAG); //设置画线 mPaintCdt.setStyle(Paint.Style.STROKE); //设置线的宽度 mPaintCdt.setStrokeWidth(lineSize); mPaintCdt.setColor(lineColor); mPaintSysPoint = new Paint(Paint.ANTI_ALIAS_FLAG); //设置填充 mPaintSysPoint.setStyle(Paint.Style.FILL); mPaintSysPoint.setColor(scalePointColor); mPaintLinePoint = new Paint(Paint.ANTI_ALIAS_FLAG); //设置填充 mPaintLinePoint.setStyle(Paint.Style.FILL); Log.i("wk","线上点的颜色:"+lineColor); mPaintLinePoint.setColor(lineColorPoint); //绘制xy轴 mPaintSys = new Paint(Paint.ANTI_ALIAS_FLAG); //设置画线 mPaintSys.setStyle(Paint.Style.STROKE); //设置线的宽度 mPaintSys.setStrokeWidth(coordinateSystemSize); mPaintSys.setColor(coordinateSystemColor); mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG); mPaintText.setTextAlign(Paint.Align.CENTER); mPaintText.setColor(Color.WHITE); mPaintText.setTextSize(30); mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG); //设置画线 mPaintLine.setStyle(Paint.Style.STROKE); //设置线的宽度 mPaintLine.setStrokeWidth(lineSize); //设置画笔的颜色 mPaintLine.setColor(lineColor); mPaintDash = new Paint(); mPaintDash.setStyle(Paint.Style.STROKE); mPaintDash.setStrokeWidth(dashSize); mPaintDash.setColor(dashColor); mPaintDash.setPathEffect(new DashPathEffect(new float[]{10,10},0)); mXBound = new Rect(); mYBound = new Rect(); invalidate(); } public ChartView(Context context, AttributeSet attrs) { super(context, attrs); //获取属性值 getAttrs(context,attrs); InitPaint(); } //获取设置的属性 private void getAttrs(Context context,AttributeSet attrs) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ChartView); //坐标系颜色 coordinateSystemColor = ta.getColor(R.styleable.ChartView_coordinateSystemColor, Color.RED); coordinateSystemSize = ta.getDimension(R.styleable.ChartView_coordinateSystemLineSize, 3f); //折线颜色 lineColor = ta.getColor(R.styleable.ChartView_lineColor, Color.BLACK); lineSize = ta.getDimension(R.styleable.ChartView_lineSize, 2f); //折线上坐标点颜色 lineColorPoint = ta.getColor(R.styleable.ChartView_linePointColor, Color.RED); //折线上坐标点的半径 lineColorPointRadius = ta.getDimension(R.styleable.ChartView_linePointRadius,6f); //刻度点颜色 scalePointColor = ta.getColor(R.styleable.ChartView_scalePointColor, Color.RED); //刻度点半径 scalePointRadius = ta.getDimension(R.styleable.ChartView_scalePointRadius, 6); //设置是否显示虚线 isShowDash = ta.getBoolean(R.styleable.ChartView_showDash,false); dashSize = ta.getDimension(R.styleable.ChartView_setDashSize,2f); dashColor = ta.getColor(R.styleable.ChartView_setDashColor, Color.WHITE); xScale = ta.getInt(R.styleable.ChartView_setXScale,5); yScale = ta.getInt(R.styleable.ChartView_setYScale,5); ta.recycle(); Log.i("wk","coordinateSystemColor:"+ coordinateSystemColor +"\n coordinateSystemSize:"+ coordinateSystemSize +"\n"+"lineColor:"+ lineColor +"\n"+"lineSize:"+ lineSize); } public ChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); getAttrs(context,attrs); InitPaint(); } //测量view @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //获取当前View的宽高 mViewWidth = w; mViewHeight = h; Log.i("wk","宽度:"+w); Log.i("wk","高度:"+h); } //绘制 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制X轴Y轴 以及原点 canvas.drawLine(Margin,mViewHeight-Margin, Margin,5, mPaintSys); canvas.drawLine(Margin,mViewHeight-Margin,mViewWidth-5,mViewHeight-Margin, mPaintSys); //绘制原点 canvas.drawCircle(Margin,mViewHeight-Margin,scalePointRadius,mPaintSysPoint); // /** * 计算两个刻度之间的间距: * * 1.刻度的个数 = 传入坐标最大的坐标点/坐标轴间距 * 2.两个刻度之间的间距 = 屏幕的宽或高 /刻度的个数 * */ int num_x = X_MAX/xScale; //x轴上需要绘制的刻度的个数 mScreenXdistance = (mViewWidth- Margin *2)/(num_x*1f); Log.i("wk","需要绘制的刻度个数==>"+num_x+"两个刻度间间隔:"+ mScreenXdistance); int num_y = Y_MAX/yScale; mScreenYdistance = (mViewHeight-Margin*2)/(num_y*1f); Log.i("wk","需要绘制的刻度个数==>"+num_x+"两个刻度间间隔:"+ mScreenXdistance); //绘制 X,y轴刻度标记 for(int i=0;i<pointList.size();i++){ canvas.drawCircle(Margin +(i* mScreenXdistance),mViewHeight-Margin,scalePointRadius,mPaintSysPoint); canvas.drawCircle(Margin,mViewHeight-Margin-(i* mScreenYdistance),scalePointRadius,mPaintSysPoint); //计算刻度字体的宽高 String index_x = String.valueOf(i*xScale); String index_y = String.valueOf(i*yScale); mPaintText.getTextBounds(index_x,0,index_x.length(),mXBound); mPaintText.getTextBounds(index_y,0,index_x.length(),mYBound); int indexWidth_x = mXBound.width(); int indexHeight_x = mXBound.height(); int indexWidth_y = mYBound.width(); int indexHeight_y = mYBound.height(); Log.i("wk","字体的宽度:"+indexWidth_x+"字体的高度:"+indexHeight_x); canvas.drawText(index_x, Margin +(i* mScreenXdistance),mViewHeight-Margin+indexHeight_x+indexHeight_x/2,mPaintText); if(i!=0) { canvas.drawText(index_y, Margin - indexHeight_y-indexWidth_y/2, mViewHeight - Margin - (i * mScreenYdistance), mPaintText); } } /** * 绘制折线 */ Point LastPoint = new Point(); //记录上一个坐标点 LastPoint.x = Margin; LastPoint.y = mViewHeight-Margin; for(int i=1;i<pointList.size();i++){ /** * 计算绘制点的坐标位置 * 绘制点的坐标 = (传入点的的最大的xy坐标/坐标轴上的间隔) * 坐标间隔对应的屏幕上的间隔 */// canvas.drawCircle(LastPoint.x,LastPoint.y,4f,mPaintPoint); //计算出脱离坐标系的点所处的位置 float point_x = (pointList.get(i).x/(xScale*1f))* mScreenXdistance; float point_y = (pointList.get(i).y/(yScale*1f))* mScreenYdistance; //坐标系内的点的位置 float startX = LastPoint.x; float startY = LastPoint.y; float endX = Margin +point_x; float endY = mViewHeight-Margin-point_y; //需要计算此处 canvas.drawLine(startX,startY,endX,endY,mPaintLine); //记录上一个坐标点的位置 LastPoint.x = (int) endX; LastPoint.y = (int) endY; if(isShowDash) { //绘制横向虚线 canvas.drawLine(Margin, mViewHeight - Margin - point_y -lineColorPointRadius/2, Margin + point_x - lineColorPointRadius/2, mViewHeight - Margin - point_y -lineColorPointRadius/2, mPaintDash); //绘制竖向虚线 canvas.drawLine(LastPoint.x, LastPoint.y, LastPoint.x, mViewHeight - Margin - lineColorPointRadius, mPaintDash); } canvas.drawCircle(LastPoint.x, LastPoint.y, lineColorPointRadius, mPaintLinePoint); } } //测量view高度 private int measureHeight(int heightMeasureSpec) { int result = 0; int specSize = MeasureSpec.getSize(heightMeasureSpec); //获取高的高度 单位 为px int specMode = MeasureSpec.getMode(heightMeasureSpec);//获取测量的模式 //如果是精确测量,就将获取View的大小设置给将要返回的测量值 if(specMode == MeasureSpec.EXACTLY){ Log.i("wk","高度:精确测量 + specSize:==>"+specSize); result = specSize; }else{ Log.i("wk","高度:UNSPECIFIED + specSize:==>"+specSize); result = 400; //如果设置成wrap_content时,给高度指定一个值 if(specMode == MeasureSpec.AT_MOST){ Log.i("wk","高度:最大值模式 + specSize:==>"+specSize); result = Math.min(result,specSize); } } return result; } //测量view宽度 private int measureWidth(int widthMeasureSpec) { int result = 0; int specSize = MeasureSpec.getSize(widthMeasureSpec); //获取高的高度 int specMode = MeasureSpec.getMode(widthMeasureSpec);//获取测量的模式 //如果是精确测量,就将获取View的大小设置给将要返回的测量值 if(specMode == MeasureSpec.EXACTLY){ Log.i("wk","宽度:精确测量 + specSize:==>"+specSize); result = specSize; }else{ Log.i("wk","宽度:UNSPECIFIED + specSize:==>"+specSize); result = 400; //如果设置成wrap_content时,给高度指定一个值 if(specMode == MeasureSpec.AT_MOST){ Log.i("wk","宽度:最大值模式 + specSize:==>"+specSize); result = Math.min(result,specSize); } } return result; }}
attrs.xml
自定义属性:
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="ChartView"> <!--设置坐标系的颜色--> <attr name="coordinateSystemColor" format="color" /> <!--设置坐标系线条的尺寸--> <attr name="coordinateSystemLineSize" format="dimension" /> <!--设置刻度点的颜色--> <attr name="scalePointColor" format="color" /> <!--设置刻度点的半径--> <attr name="scalePointRadius" format="dimension" /> <!--设置折线的颜色--> <attr name="lineColor" format="color" /> <!--设置着折线的宽度--> <attr name="lineSize" format="dimension" /> <!--设置折线点的颜色--> <attr name="linePointColor" format="color" /> <!--设置折线点的半径--> <attr name="linePointRadius" format="dimension" /> <!--设置是否显示虚线--> <attr name="showDash" format="boolean" /> <attr name="setDashSize" format="dimension"/> <attr name="setDashColor" format="color"/> <!--设置坐标轴上刻度的间隔--> <attr name="setXScale" format="integer" /> <attr name="setYScale" format="integer" /> </declare-styleable></resources>
activity_main.xml
<com.merpyzf.studymultimedia.ChartView android:id="@+id/myChartView" android:layout_marginTop="20dp" android:background="@color/colorPrimary" android:layout_width="match_parent" android:layout_height="600dp" app:linePointColor="@color/colorAccent" app:scalePointColor="#f76" app:linePointRadius="5dp" app:lineColor="#fff600" app:lineSize="2dp" app:coordinateSystemColor="#000000" app:coordinateSystemLineSize="2dp" app:scalePointRadius="6dp" app:setDashSize="1dp" app:showDash="true" />
MainActivity.java
public class MainActivity extends AppCompatActivity { private MyService.MyBinder myBinder; private ChartView MyChartView; private ArrayList<Point> pointList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyChartView = (ChartView) findViewById(R.id.myChartView); Random random = new Random(); pointList = new ArrayList<Point>(); for(int i=0;i<=10;i++){ Point p = new Point(i*5,random.nextInt(30)); pointList.add(p); } //给ChartView设置坐标 MyChartView.setPoint(pointList); }}
后面要花一段时间仔细的研究一下自定义View的知识,当然上面的这个折线图只是脑子一热敲出来的,不具备实用能力(⊙o⊙)…
量变引起质变
撒花 撒花 ^^O(∩∩)O哈哈~
0 0
- 安卓自定义View实现简单折线图
- 自定义View简单折线图
- Android自定义View实现简单的折线图、柱状图
- 自定义View:画布实现自定义View(折线图的实现)
- Android 自定义View,实现折线图
- Android 自定义View,实现折线图
- 自定义View实现天气折线图效果
- WeatherView -- 自定义View实现天气折线图
- 自定义view实现画折线图
- 自定义View--折线图
- 自定义View折线图
- 自定义View折线图
- 折线图 自定义折线图 自定义view
- 安卓自定义控件之折线图
- 自定义View之折线图
- 自定义View,画折线图
- 自定义view—折线图
- 自定义view—折线图
- HDU 1251 统计难题
- git创建分支添加远程仓库上传
- 元素只能在固定窗口内拖动
- codeforces 617E. XOR and Favorite Number (莫队)
- Linux中数据库mysqladmin登录错误的解决办法
- 安卓自定义View实现简单折线图
- Caffe框架的理解(一):从blob到layer到net
- 天梯赛模拟题- N个数求和
- 八皇后问题(减支思想、全列举)
- Python Wiki
- CSS下的图片精灵
- RxBus的实现及简单使用
- Android_lottery_summary
- TensorFlow简要教程系列(二)TensorFlow基本操作