版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33776306/article/details/52869167
最近做了一个类似天气预告的demo,其中有一个自定义折线图,在网上找了很多例子,没有一个合适的,于是只能参考别人的例子,根据自己的想法写了一套demo.
在做自定义控件之前,先熟悉一下paint和canvas的简单使用。
链接:http://blog.csdn.net/qq_33776306/article/details/52290729
大概的思路无非就是先画一个横纵坐标,然后根据点的X轴Y轴的坐标,进行画点画线画文字。
最后的效果图呢如下
然后接下来看定义的折线图控件了
<span style="color:#009900;">package com.yang.draw;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
class MyChartView extends View{
public static final int RECT_SIZE = 10;
//枚举实现坐标桌面的样式风格
public static enum Mstyle
{
Line,Curve
}
private Mstyle mstyle=Mstyle.Line;
private Point[] mPoints = new Point[100];
Context context;
int bheight=0;
HashMap<Double, Double> map;
ArrayList<Double> dlk;
int totalvalue=30;
int pjvalue=5;
String xstr,ystr="";//横纵坐标的属性
int margint=15;
int marginb=40;
int c=0;
int resid=0;
Boolean isylineshow;
/**
*
*/
public void SetTuView(HashMap<Double, Double> map,int totalvalue,int pjvalue,String xstr,String ystr,Boolean isylineshow)
{
this.map=map;
this.totalvalue=totalvalue;
this.pjvalue=pjvalue;
this.xstr=xstr;
this.ystr=ystr;
this.isylineshow=isylineshow;
}
public MyChartView(Context ct)
{
super(ct);
this.context=ct;
}
public MyChartView(Context ct, AttributeSet attrs)
{
super( ct, attrs );
this.context=ct;
}
public MyChartView(Context ct, AttributeSet attrs, int defStyle)
{
super( ct, attrs, defStyle );
this.context=ct;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(c!=0)
this.setbg(c);
if(resid!=0)
this.setBackgroundResource(resid);
dlk=getintfrommap(map);
int height=getHeight();
if(bheight==0)
bheight=height-marginb;
int width=getWidth();
int blwidh=dip2px(context,50);
int pjsize=totalvalue/pjvalue;//界面布局的尺寸的比例
// set up paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.GRAY);
paint.setStrokeWidth(1);
paint.setStyle(Style.STROKE);
for(int i=0;i<pjsize+1;i++)//将顶点的线变为红色的 警戒线
{
if(i==pjsize)
paint.setColor(Color.RED);
canvas.drawLine(blwidh,bheight-(bheight/pjsize)*i+margint,width,bheight-(bheight/pjsize)*i+margint, paint);//Y坐标
drawline(pjvalue*i+"°", blwidh/2, bheight-(bheight/pjsize)*i+margint, canvas);
}
ArrayList<Integer> xlist=new ArrayList<Integer>();//记录每个x的值
//画直线(纵向)
paint.setColor(Color.GRAY);
if(dlk==null)
return;
for(int i=0;i<dlk.size();i++)
{
xlist.add(blwidh+(width-blwidh)/dlk.size()*i);
if(isylineshow)
{
canvas.drawLine(blwidh+(width-blwidh)/dlk.size()*i,margint,blwidh+(width-blwidh)/dlk.size()*i,bheight+margint, paint);
}
String day=null;
if(dlk.get(i)==1.0){
day="Mon";
}else if(dlk.get(i)==2.0){
day="Tue";
}else if(dlk.get(i)==3.0){
day="Wed";
}else if(dlk.get(i)==4.0){
day="Thu";
}else if(dlk.get(i)==5.0){
day="Fir";
}else if(dlk.get(i)==6.0){
day="Sat";
}else if(dlk.get(i)==7.0){
day="Sun";
}
drawline(day, blwidh+(width-blwidh)/dlk.size()*i, bheight+40, canvas);//X坐标
}
//点的操作设置
mPoints=getpoints(dlk, map, xlist, totalvalue, bheight);
paint.setColor(Color.GREEN);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(0);
if(mstyle==Mstyle.Curve)
drawscrollline(mPoints, canvas, paint);
else
drawline(mPoints, canvas, paint);
paint.setColor(Color.RED);
paint.setStyle(Style.FILL);
for (int i=0; i<mPoints.length; i++)
{
canvas.drawRect(pointToRect(mPoints[i]),paint);
//给点加上文字,也就是温度,温度其实就是map的values值。
float indexty=(mPoints[i].y - RECT_SIZE/2+ mPoints[i].y + RECT_SIZE/2)/2;//y轴坐标
canvas.drawText(getValues(i+1.0)+"°", mPoints[i].x + RECT_SIZE/2+10, indexty, paint);
}
}
private RectF pointToRect(Point p)
{
return new RectF(p.x -RECT_SIZE/2, p.y - RECT_SIZE/2,p.x + RECT_SIZE/2, p.y + RECT_SIZE/2);
}
private void drawscrollline(Point[] ps,Canvas canvas,Paint paint)
{
Point startp=new Point();
Point endp=new Point();
for(int i=0;i<ps.length-1;i++)
{
startp=ps[i];
endp=ps[i+1];
int wt=(startp.x+endp.x)/2;
Point p3=new Point();
Point p4=new Point();
p3.y=startp.y;
p3.x=wt;
p4.y=endp.y;
p4.x=wt;
Path path = new Path();
path.moveTo(startp.x,startp.y);
path.cubicTo(p3.x, p3.y, p4.x, p4.y,endp.x, endp.y);
canvas.drawPath(path, paint);
}
}
private void drawline(Point[] ps,Canvas canvas,Paint paint)
{
Point startp=new Point();
Point endp=new Point();
for(int i=0;i<ps.length-1;i++)
{
startp=ps[i];
endp=ps[i+1];
canvas.drawLine(startp.x,startp.y,endp.x,endp.y, paint);
}
}
private Point[] getpoints(ArrayList<Double> dlk,HashMap<Double, Double> map,ArrayList<Integer> xlist,int max,int h)
{
Point[] points=new Point[dlk.size()];
for(int i=0;i<dlk.size();i++)
{
int ph=h-(int)(h*(map.get(dlk.get(i))/max));
points[i]=new Point(xlist.get(i),ph+margint);
}
return points;
}
private void drawline(String text,int x,int y,Canvas canvas)
{
Paint p = new Paint();
p.setAlpha(0x0000ff);
p.setTextSize(20);
String familyName = "宋体";
Typeface font = Typeface.create(familyName,Typeface.BOLD);
p.setTypeface(font);
p.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, x, y, p);
}
public int dip2px(Context context, float dpValue)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public int px2dip(Context context, float pxValue)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
//获取map中的key键对应的values值
private Double getValues(Double d){
Object obj = new Object();
obj = map.get(d);
return (Double) obj;
}
//获取map集合中key的值
@SuppressWarnings("rawtypes")
public ArrayList<Double> getintfrommap(HashMap<Double, Double> map)
{
ArrayList<Double> dlk=new ArrayList<Double>();
int position=0;
if(map==null)
return null;
Set set= map.entrySet();
Iterator iterator = set.iterator();
while(iterator.hasNext())
{
@SuppressWarnings("rawtypes")
Map.Entry mapentry = (Map.Entry)iterator.next();
Double s=(Double)mapentry.getKey();
dlk.add((Double)mapentry.getKey());//获取map中的key值,获取到的值是无序的
}
//对key值进行有序的排列,
for(int i=0;i<dlk.size();i++)
{
int j=i+1;
position=i;
Double temp=dlk.get(i);
for(;j<dlk.size();j++)
{
if(dlk.get(j)<temp)
{
temp=dlk.get(j);
position=j;
}
}
dlk.set(position,dlk.get(i));
dlk.set(i,temp);
}
return dlk;
}
public void setbg(int c)
{
this.setBackgroundColor(c);
}
public HashMap<Double, Double> getMap() {
return map;
}
public void setMap(HashMap<Double, Double> map) {
this.map = map;
// invalidate();//这里进行重绘,如果在给map赋值之前执行了onDraw方法,则调用此方法,否则不需要。
}
public int getTotalvalue() {
return totalvalue;
}
public void setTotalvalue(int totalvalue) {
this.totalvalue = totalvalue;
}
public int getPjvalue() {
return pjvalue;
}
public void setPjvalue(int pjvalue) {
this.pjvalue = pjvalue;
}
public String getXstr() {
return xstr;
}
public void setXstr(String xstr) {
this.xstr = xstr;
}
public String getYstr() {
return ystr;
}
public void setYstr(String ystr) {
this.ystr = ystr;
}
public int getMargint() {
return margint;
}
public void setMargint(int margint) {
this.margint = margint;
}
public Boolean getIsylineshow() {
return isylineshow;
}
public void setIsylineshow(Boolean isylineshow) {
this.isylineshow = isylineshow;
}
public int getMarginb() {
return marginb;
}
public void setMarginb(int marginb) {
this.marginb = marginb;
}
public Mstyle getMstyle() {
return mstyle;
}
public void setMstyle(Mstyle mstyle) {
this.mstyle = mstyle;
}
public int getBheight() {
return bheight;
}
public void setBheight(int bheight) {
this.bheight = bheight;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
public int getResid() {
return resid;
}
public void setResid(int resid) {
this.resid = resid;
}
} </span>
代码中一些注释都已经标注,大部分都是一些paint和canvas的用法了,参考链接的文章就可以。
最后就是在主代码中给温度赋值了
<span style="color:#009900;">package com.yang.draw;
import java.util.HashMap;
import java.util.Timer;
import com.yang.draw.MyChartView.Mstyle;
import com.yzxy.draw.R;
import android.os.Bundle;
import android.widget.Button;
import android.app.Activity;
public class MainActivity extends Activity {
MyChartView tu;
Button BT_Add;
Timer mTimer =new Timer();
HashMap<Double, Double> map;
Double key=8.0;
Double value=0.0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BT_Add=(Button)findViewById(R.id.bt_add);
tu= (MyChartView)findViewById(R.id.menulist);
tu.SetTuView(map,50,10,"x","y",false);
map=new HashMap<Double, Double>();
map.put(1.0, 13.0);
map.put(2.0, 25.0);
map.put(3.0, 32.0);
map.put(4.0, 31.0);
map.put(5.0, 16.0);
map.put(6.0, 36.0);
map.put(7.0, 26.0);
tu.setTotalvalue(50);
tu.setPjvalue(10);
tu.setMap(map);
tu.setMargint(20);
tu.setMarginb(50);
tu.setMstyle(Mstyle.Line);
}
}</span>
其中大家要注意的是,我在给控件赋值时(tu.setMap(map)),onDraw方法还未执行,所以我将控件中的重绘方法invalidate()给注掉了,所以提醒大家,如果tu.setMap(map)执行比较靠后的话,在自定义控件中,给map赋值后加上重绘方法
invalidate()。