Android 折線圖的實現

小壞楠楠發表於2015-07-27

對於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;

}

}


MainActivity.Java

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);

}

});

}

}



相關文章