android自定義折線圖——之簡單的溫度折線圖
阿新 • • 發佈:2019-02-07
最近做了一個類似天氣預告的demo,其中有一個自定義折線圖,在網上找了很多例子,沒有一個合適的,於是只能參考別人的例子,根據自己的想法寫了一套demo.
在做自定義控制元件之前,先熟悉一下paint和canvas的簡單使用。
大概的思路無非就是先畫一個橫縱座標,然後根據點的X軸Y軸的座標,進行畫點畫線畫文字。
最後的效果圖呢如下
然後接下來看定義的折線圖控制元件了
程式碼中一些註釋都已經標註,大部分都是一些paint和canvas的用法了,參考連結的文章就可以。<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>
最後就是在主程式碼中給溫度賦值了
其中大家要注意的是,我在給控制元件賦值時(tu.setMap(map)),onDraw方法還未執行,所以我將控制元件中的重繪方法invalidate()給注掉了,所以提醒大家,如果tu.setMap(map)執行比較靠後的話,在自定義控制元件中,給map賦值後加上重繪方法invalidate()。<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>