andoid 自定义view 画折线图
1 这个主要包含了简单的绘图操作 还是比较简单的
2 说一下原理把 首先根据价格的最大值和最小只的差异获取比例,然后在找一个最低点作为价格最低点
3 把说有点连起来用path画一个多边形
4 然后在划线,最后画小原点
5 要注意DrawText 的起点的xy坐标,和android 坐标系
package com.che300.price.component; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import com.che300.price.R; import com.che300.price.util.UIUtil; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2016/6/23. */ /* LineChartView m = (LineChartView) findViewById(R.id.LineChartView); // 这边是调用demo List<LineChartView.ItemInfo> infos = new ArrayList<>(); LineChartView.ItemInfo info = new LineChartView.ItemInfo(14.36f,"201612"); LineChartView.ItemInfo info1 = new LineChartView.ItemInfo(11.36f,"201613"); LineChartView.ItemInfo info2 = new LineChartView.ItemInfo(13.36f,"201615"); LineChartView.ItemInfo info3 = new LineChartView.ItemInfo(12.36f,"201612"); LineChartView.ItemInfo info4= new LineChartView.ItemInfo(11.36f,"201612"); LineChartView.ItemInfo info5= new LineChartView.ItemInfo(11.36f,"201612"); infos.add(info); infos.add(info1); infos.add(info2); infos.add(info3); infos.add(info4); infos.add(info5); m.setPrices(infos); <com.che300.price.component.LineChartView 这里是布局 android:id="@+id/LineChartView" android:layout_width="match_parent" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_height="wrap_content" /> */ public class LineChartView extends View { private Paint mpaint; private int width, heigth; private final int DEFAULTWIDTH= 200; // 标注下的高度150dp private Context context_; public List<ItemInfo> prices = new ArrayList<>(); public List<PointF> pointFs = new ArrayList<>(); public int pricetipsize ; public void setPrices(List<ItemInfo> prices) { this.prices.clear(); this.prices.addAll(prices); invalidate(); } public LineChartView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public LineChartView(Context context) { super(context); } public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void init(Context context) { this.context_ = context; mpaint = new Paint(); mpaint.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthmode = MeasureSpec.getMode(widthMeasureSpec); int hightmode = MeasureSpec.getMode(heightMeasureSpec); int widthsize = MeasureSpec.getSize(widthMeasureSpec); int higthsize = MeasureSpec.getSize(heightMeasureSpec); if (widthmode == MeasureSpec.EXACTLY) { width = widthsize; } else { width = UIUtil.getDisplayMetrics(context_).widthPixels; } if (hightmode == MeasureSpec.EXACTLY) { heigth = higthsize; } else { heigth = UIUtil.dp2pxInt(context_, 200); } setMeasuredDimension(width, heigth); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mpaint.setColor(getResources().getColor(R.color.back)); mpaint.setStrokeWidth(3); drawBackgrondLine(canvas); if (prices.size() == 0) { return; } initPricetipsize(); drawPoint(canvas); drawPointText(canvas); drawCanvasBg(canvas); drawPointOval(canvas); drawCanvasButtom(canvas); } public void initPricetipsize(){ pricetipsize = getDefaultTipSize(); } public void drawBackgrondLine(Canvas canvas) { mpaint.setColor(getResources().getColor(R.color.line)); int margin = heigth / 4; for (int i = 0; i < 4; i++) { canvas.drawLine(0, i * margin, width, i * margin, mpaint); } } public void drawPointOval(Canvas canvas){ mpaint.setStrokeWidth(3); for (int i = 0; i < pointFs.size(); i++) { PointF p = pointFs.get(i); mpaint.setColor(Color.WHITE); mpaint .setStyle(Paint.Style. FILL ); RectF mArc = new RectF(p.x-UIUtil.dp2pxInt(context_,4), p.y-UIUtil.dp2pxInt(context_,4), p.x+UIUtil.dp2pxInt(context_,4), p.y+UIUtil.dp2pxInt(context_,4)); canvas.drawArc(mArc,0f,360f,true,mpaint); mpaint .setColor(Color.argb(0x44, 0xff, 0x66, 0x00)); canvas.drawArc(mArc,0f,360f,true,mpaint); mpaint .setColor(getResources().getColor(R.color.orange) ); //设置画笔颜色 mpaint .setStyle(Paint.Style. STROKE ); RectF mArc1 = new RectF(p.x-UIUtil.dp2pxInt(context_,4), p.y-UIUtil.dp2pxInt(context_,4), p.x+UIUtil.dp2pxInt(context_,4), p.y+UIUtil.dp2pxInt(context_,4)); canvas.drawArc(mArc1,0f,360f,true,mpaint); } } public void drawPoint(Canvas canvas){ mpaint .setColor(getResources().getColor(R.color.orange) ); for (int i = 0; i < prices.size(); i++) { PointF p = getStartPostion(i,prices.get(i).getPrice()); pointFs.add(p); } for (int i = 0; i < pointFs.size(); i++) { if (i == pointFs.size() - 1) { return; } PointF p = pointFs.get(i); PointF p1 = pointFs.get(i + 1); canvas.drawLine(p.x , p.y, p1.x , p1.y, mpaint); } for (int i = 0; i < prices.size(); i++) { PointF p = getStartPostion(i,prices.get(i).getPrice()); pointFs.add(p); mpaint.setColor(Color.WHITE); // mpaint .setColor(Color.argb(0x66, 0xff, 0x66, 0x00)); //设置画笔颜色 mpaint .setStyle(Paint.Style. FILL ); RectF mArc = new RectF(p.x-UIUtil.dp2pxInt(context_,4), p.y-UIUtil.dp2pxInt(context_,4), p.x+UIUtil.dp2pxInt(context_,4), p.y+UIUtil.dp2pxInt(context_,4)); canvas.drawArc(mArc,0f,360f,true,mpaint); mpaint .setColor(Color.argb(0x44, 0xff, 0x66, 0x00)); canvas.drawArc(mArc,0f,360f,true,mpaint); mpaint .setColor(getResources().getColor(R.color.orange) ); //设置画笔颜色 mpaint .setStyle(Paint.Style. STROKE ); RectF mArc1 = new RectF(p.x-UIUtil.dp2pxInt(context_,4), p.y-UIUtil.dp2pxInt(context_,4), p.x+UIUtil.dp2pxInt(context_,4), p.y+UIUtil.dp2pxInt(context_,4)); canvas.drawArc(mArc1,0f,360f,true,mpaint); } } public void drawPointText(Canvas canvas){ mpaint.setColor(Color.BLACK); mpaint.setTextSize(pricetipsize); mpaint.setStyle(Paint.Style.FILL); mpaint.setStrokeWidth(2); for (int i = 0; i < pointFs.size(); i++) { PointF p = pointFs.get(i); canvas.drawText(String.valueOf(prices.get(i).getPrice()),p.x-(getDefaultTipSizeWidth()/2),p.y-UIUtil.dp2pxInt(context_,8),mpaint); // 8 是又圆心到上面的距离 5+3 } } public void drawCanvasBg( Canvas canvas){ mpaint.setStyle(Paint.Style.FILL); mpaint.setColor(Color.argb(0x44, 0xff, 0x66, 0x00)); Path path= new Path(); for (int i = 0; i < pointFs.size(); i++) { PointF p = pointFs.get(i); path.lineTo(p.x,p.y); if (i==pointFs.size()-1){ path.lineTo(p.x,heigth*3/4); path.lineTo(pointFs.get(0).x,heigth*3/4); path.lineTo(pointFs.get(0).x,pointFs.get(0).y); } } canvas.drawPath(path,mpaint); } public void drawCanvasButtom( Canvas canvas){ mpaint.setStyle(Paint.Style.FILL); mpaint.setColor(Color.BLACK); mpaint.setTextSize(pricetipsize); mpaint.setStrokeWidth(3); for (int i = 0; i <= pointFs.size(); i++) { int buttomwidth = width/pointFs.size(); mpaint.setColor(getResources().getColor(R.color.line)); canvas.drawLine(buttomwidth*i,heigth*3/4,buttomwidth*i,heigth*3/4+getDefaultScale()*UIUtil.dp2pxFloat(context_,10),mpaint); mpaint.setColor(getResources().getColor(R.color.text2)); if (i==pointFs.size()){ return; } canvas.drawText(prices.get(i).getYear(),buttomwidth*i+(buttomwidth-getDefaultScale()*UIUtil.dp2pxInt(context_,38))/2 ,heigth*3/4+pricetipsize+UIUtil.dp2pxInt(context_,10)*getDefaultScale(),mpaint); } } public float getDeviationPrice() { // 获取最大与最小值直接的差值 float max = 0; for (ItemInfo info : prices) { if (info.price >= max) { max = info.price; } } return max - getMinPrice(); } public float getMinPrice() { // 获取最大与最小值直接的差值 float min = Integer.MAX_VALUE; for (ItemInfo info : prices) { if (info.price<=min){ min=info.price; } } return min; } public PointF getStartPostion(int postion , float price){ PointF p = new PointF(); int contentheight = heigth*1/4 -(pricetipsize+UIUtil.dp2pxInt(context_, 10)); p.y = contentheight-(price-getMinPrice())*contentheight/getDeviationPrice()+(pricetipsize+UIUtil.dp2pxInt(context_, 10)); // 这个10dp 是默认留白 p.x = width/prices.size()*postion+width/(2*prices.size()); return p; } public int getDefaultTipSize(){ return (int)(getDefaultScale()*UIUtil.dp2pxInt(context_,15)); } public int getDefaultTipSizeWidth(){ //30 是在prd 上面的标注默认值 return (int)(getDefaultScale()*UIUtil.dp2pxInt(context_,30)); } public int getDefaultButtomHeight(){ //30 是在prd 上面的标注默认值 return (int)(getDefaultScale()*UIUtil.dp2pxInt(context_,10)); //底部10dip } public float getDefaultScale(){ return (heigth*3/4)/ (float)UIUtil.dp2pxInt(context_, DEFAULTWIDTH); } public static class ItemInfo{ private float price; private String year; public ItemInfo(float price, String year) { this.price = price; this.year = year; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } } }