Android 折線圖的實現
對於Android折線圖,我做了許多,滑動的,不可滑動的,點選彈框的等等,在這裡跟大家分享下今天剛寫的一個不可滑動的折線圖
首先說下大概思路:
CoordinateBase 作為一個基類,只負責點座標的運算;LineView 這個類繼承自CoordinateBase,主要負責根據點的座標去繪製canvas。
直接上原始碼,程式碼不難,看看就會了,大家如果有問題可以留言,發現bug更好,在這裡先感謝大家。
CoordinateBase.java
public abstract class CoordinateBase extends View {
private final Boolean isLog = false;
private Context context;
protected Rect mRect = new Rect(0, 0, 720, 1280);
private float ratioX, ratioY;
private ArrayList<ArrayList<CoorPoint>> pointArr = new ArrayList<ArrayList<CoorPoint>>();
private int maxValue = 250, minValue = 0;
private float xTemp, yTemp;
private float xAreaHeight;
protected float density;
private float marginLength;
private Boolean displaySelectLine = false;
private float xInterval;
private float pointSize;
private int lastSelectPosition = -1;
public CoordinateBase(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initParams(context);
}
public CoordinateBase(Context context, AttributeSet attrs) {
super(context, attrs);
initParams(context);
}
public CoordinateBase(Context context) {
super(context);
initParams(context);
}
private void initParams(Context context) {
this.context = context;
this.density = context.getResources().getDisplayMetrics().density;
int[] params = extremeSetting();
if (params != null && params.length == 2) {
minValue = params[0];
maxValue = params[1];
}
if (isLog) {
Log.i("Jiaqi", "minValue = " + minValue);
Log.i("Jiaqi", "maxValue = " + maxValue);
}
this.setClickable(true);
this.setOnTouchListener(mOnTouchListener);
}
protected abstract int[] extremeSetting();
protected abstract float xAreaHeightSetting();
protected abstract float marginLengthSetting();
protected abstract ArrayList<ArrayList<CoorPoint>> dataInput();
protected abstract void drawLine(Canvas canvas, float ratioX, float ratioY);
protected abstract void drawAreas(Canvas canvas, float ratioX, float ratioY);
protected abstract void drawSelectLine(Canvas canvas, float ratioX, float ratioY,int selectPosition);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (isLog) {
Log.i("Jiaqi", "onMeasure");
}
xAreaHeight = xAreaHeightSetting();
marginLength = marginLengthSetting();
ratioX = this.getMeasuredWidth() * 1f / 720;
ratioY = this.getMeasuredHeight() * 1f / 1280;
pointArr = dataInput();
if (pointArr != null) {
for (int i = 0; i < pointArr.size(); i++) {
if (pointArr.get(i) != null && pointArr.get(i).size() > 0) {
calculateXY(pointArr.get(i));
}
}
}
if (isLog) {
Log.i("Jiaqi", "Calculating Over");
}
}
private void calculateXY(ArrayList<CoorPoint> pointArr) {
pointSize = pointArr.get(0).getSize();
xInterval = (720 * ratioX - 2 * pointSize - marginLength * 2) / (pointArr.size() - 1);
float yInterval = (1280 * ratioY - pointSize - xAreaHeight) / (maxValue - minValue);
if (isLog) {
Log.i("Jiaqi", "xAreaHeight = " + xAreaHeight);
}
for (int i = 0; i < pointArr.size(); i++) {
xTemp = marginLength + pointSize + i * xInterval;
yTemp = 1280 * ratioY - xAreaHeight - yInterval * pointArr.get(i).getyValue();
pointArr.get(i).setX(xTemp);
pointArr.get(i).setY(yTemp);
}
}
private void searchSelectPosition(float touchX)
{
int position = -1;
if(pointArr!=null&&pointArr.size()>0){
position = (int) ((touchX - pointSize - marginLength - xInterval/2)/xInterval);
for(int i = 0;i<pointArr.size();i++){
if(position>=pointArr.get(i).size()){
position = -1;
break;
}
}
}
if(position>=0&&lastSelectPosition!=position){
invalidate();
}
lastSelectPosition = position;
}
private OnTouchListener mOnTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
displaySelectLine = true;
searchSelectPosition(event.getX());
break;
case MotionEvent.ACTION_MOVE:
searchSelectPosition(event.getX());
break;
case MotionEvent.ACTION_UP:
displaySelectLine = false;
invalidate();
break;
default:
break;
}
return false;
}
};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isLog) {
Log.i("Jiaqi", "onDraw");
}
drawAreas(canvas, ratioX, ratioY);
drawLine(canvas, ratioX, ratioY);
if(displaySelectLine){
if(lastSelectPosition>=0){
drawSelectLine(canvas, ratioX, ratioY, lastSelectPosition);
}
}
}
public void setDisplaySelectLine(Boolean displaySelectLine) {
this.displaySelectLine = displaySelectLine;
}
public Boolean getDisplaySelectLine() {
return displaySelectLine;
}
}
LineView.java
public class LineView extends CoordinateBase {
/**樣式相關引數,可修改**/
private final int maxValue = 300;
private final int minValue = 0;
private float areasHeight;
private float textSize;
private int[] lineColors = null;
/**其餘引數,請勿修改**/
private final Boolean isLog = false;
private Context context;
private ArrayList<ArrayList<CoorPoint>> data = null;
private DataEnterListener mDataListener = null;
private SelectListener mSelectListener = null;
private Paint coorPaint = null, textPaint = null, linePaint = null, pointPaint = null;
public LineView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
/**座標軸高度 座標文字大小**/
this.areasHeight = 50 * density;
this.textSize = 11*density;
initPaint();
}
private void initPaint() {
this.coorPaint = new Paint();
this.coorPaint.setAntiAlias(true);
this.coorPaint.setColor(0xff999999);
this.coorPaint.setStrokeWidth(0.5f * density);
this.coorPaint.setAlpha(255);
this.coorPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.textPaint = new Paint();
this.textPaint.setAntiAlias(true);
this.textPaint.setColor(0xff999999);
this.textPaint.setAlpha(255);
this.textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.textPaint.setTypeface(Typeface.DEFAULT);
this.textPaint.setTextSize(textSize);
this.textPaint.setTextAlign(Align.CENTER);
this.linePaint = new Paint();
this.linePaint.setAntiAlias(true);
this.linePaint.setColor(0xff999999);
this.linePaint.setStrokeWidth(1f * density);
this.linePaint.setAlpha(255);
this.linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.pointPaint = new Paint();
this.pointPaint.setAntiAlias(true);
this.pointPaint.setColor(0xff999999);
this.pointPaint.setStrokeWidth(0f);
this.pointPaint.setAlpha(255);
this.pointPaint.setStyle(Paint.Style.FILL);
}
public void setPaintColor(int coorColor, int[] lineColors) {
this.coorPaint.setColor(coorColor);
this.textPaint.setColor(coorColor);
this.lineColors = lineColors;
invalidate();
}
@Override
protected int[] extremeSetting() {
int[] extreme = new int[2];
extreme[0] = minValue;// minValue
extreme[1] = maxValue;// maxValue
return extreme;
}
@Override
protected float xAreaHeightSetting() {
return areasHeight;
}
@Override
protected float marginLengthSetting() {
return 20*density;
}
@Override
protected ArrayList<ArrayList<CoorPoint>> dataInput() {
data = null;
if (mDataListener != null) {
data = mDataListener.setData();
}
return data;
}
@Override
protected void drawLine(Canvas canvas, float ratioX, float ratioY) {
if (data != null) {
for (int index = 0; index < data.size(); index++) {
ArrayList<CoorPoint> dataItem = data.get(index);
if (lineColors != null && index < lineColors.length) {
linePaint.setColor(lineColors[index]);
}
for (int i = 0; i < dataItem.size() - 1; i++) {
/** drawLine **/
canvas.drawLine(dataItem.get(i).getX(), dataItem.get(i).getY(), dataItem.get(i + 1).getX(), dataItem.get(i + 1).getY(), linePaint);
pointPaint.setColor(dataItem.get(i).getPointColor());
/** drawPoint **/
canvas.drawCircle(dataItem.get(i).getX(), dataItem.get(i).getY(), dataItem.get(i).getSize(), pointPaint);
}
/**the last one point**/
pointPaint.setColor(dataItem.get(dataItem.size() - 1).getPointColor());
canvas.drawCircle(dataItem.get(dataItem.size() - 1).getX(), dataItem.get(dataItem.size() - 1).getY(), dataItem.get(dataItem.size() - 1).getSize(), pointPaint);
}
}
}
@Override
protected void drawAreas(Canvas canvas, float ratioX, float ratioY) {
if (areasHeight > 0) {
if (isLog) {
Log.i("Jiaqi", "LineView->mRect.width = " + mRect.width());
Log.i("Jiaqi", "LineView->mRect.height = " + mRect.height());
Log.i("Jiaqi", "LineView->ratioX = " + ratioX);
Log.i("Jiaqi", "LineView->ratioY = " + ratioY);
}
canvas.drawLine(0f, mRect.height() * ratioY - areasHeight, mRect.width() * ratioX, mRect.height() * ratioY - areasHeight, coorPaint);
if(data.size()>0){
ArrayList<CoorPoint> dataItem = data.get(0);
if(dataItem!=null){
for(int i = 0;i<dataItem.size();i++){
canvas.drawText(dataItem.get(i).getxValue(), dataItem.get(i).getX(), mRect.height() * ratioY - areasHeight + textSize*3/2, textPaint);
}
}
}
}
}
@Override
protected void drawSelectLine(Canvas canvas, float ratioX, float ratioY, int selectPosition) {
canvas.drawLine(data.get(0).get(selectPosition).getX(), 0, data.get(0).get(selectPosition).getX(), 1280*ratioY-areasHeight, coorPaint);
if(mSelectListener!=null){
mSelectListener.getPosition(selectPosition);
}
}
/**介面**/
public interface DataEnterListener {
public ArrayList<ArrayList<CoorPoint>> setData();
}
public void setDataEnterListener(DataEnterListener mListener) {
this.mDataListener = mListener;
}
public interface SelectListener{
public void getPosition(int position);
}
public void setSelectListener(SelectListener mListener)
{
this.mSelectListener = mListener;
}
}
public class MainActivity extends Activity {
private ArrayList<ArrayList<CoorPoint>> data = new ArrayList<ArrayList<CoorPoint>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
InitViews();
}
private void InitViews() {
/** 每個dataItem中的CoorPoint數量一定要一樣!!!**/
ArrayList<CoorPoint> dataItem = new ArrayList<CoorPoint>();
for (int i = 0; i < 20; i++) {
dataItem.add(new CoorPoint(8, i + "", (int) (100 + 50 * Math
.random()), 0xffff0000, true));
}
data.add(dataItem);
dataItem = new ArrayList<CoorPoint>();
for (int i = 0; i < 20; i++) {
dataItem.add(new CoorPoint(8, i + "", (int) (200 + 50 * Math
.random()), 0xff0000ff, true));
}
data.add(dataItem);
LineView line = (LineView) findViewById(R.id.lineview);
line.setPaintColor(0xff999999, new int[] { 0xffff0000, 0xff0000ff });
line.setDataEnterListener(new DataEnterListener() {
@Override
public ArrayList<ArrayList<CoorPoint>> setData() {
return data;
}
});
line.setSelectListener(new SelectListener() {
@Override
public void getPosition(int position) {
Log.i("XiaoHuai", "selectPosition = " + position);
}
});
}
}
相關文章
- Flutter 實現平滑曲線折線圖Flutter
- MVC實現EChatrs動態折線圖MVC
- Android開發自定義控制元件實現一個折線圖Android控制元件
- 自定義View:畫布實現自定義View(折線圖的實現)View
- Android 折線圖之hellocharts (餅狀圖)餅圖Android
- Android之自定義控制元件實現天氣溫度折線圖和餅狀圖Android控制元件
- java實現各種資料統計圖(柱形圖,餅圖,折線圖)Java
- Android 上自定義的複式折線圖(二)Android
- Android 上自定義的複式折線圖(一)Android
- 微信小程式折線圖表折線圖加區域圖微信小程式
- R : 折線圖
- JFreeChart在Struts2中折線圖統計的實現
- echarts 折線圖拼接Echarts
- canvas圖表(2) - 折線圖Canvas
- excel折線圖自定x軸y軸 excel折線圖xy設定Excel
- ECHARTS-折線圖不顯示資料 控制折線圖顏色Echarts
- matlab畫折線圖Matlab
- java作折線圖(轉)Java
- PyQtGraph繪製折線圖QT
- AnyChart繪製折線圖
- Android仿火幣K線圖實現Android
- Echarts資料視覺化:圖表篇(2)—— 折線圖、堆疊面積折線圖Echarts視覺化
- Excel 散點圖和折線圖的區別Excel
- Android簡易柱狀圖和曲線圖表實現Android
- EXCEL 2010折線圖出現斷線怎麼辦?Excel
- MATLAB 繪製折線圖Matlab
- PHP 生成折線圖和餅圖等PHP
- 前端使用 Konva 實現視覺化設計器(22)- 繪製圖形(矩形、直線、折線)前端視覺化
- amCharts繪製帶趨勢線折線圖
- Python畫圖——matplotlib(普通折線圖)Python
- python畫散點圖和折線圖Python
- 在Excel股價圖中新增折線圖Excel
- Android studio實現圖示方式展示資訊(折線圖等)時com.github.mikephil.charting.charts.LineChart標紅AndroidGithub
- D3.js上手——折線圖JS
- Python視覺化-折線圖Python視覺化
- echart折線圖異常多出一條連線線
- 資料視覺化圖表之折線圖視覺化
- amCharts繪製折線圖和柱狀圖混合