android实现折线图和柱状图
2017-09-26 17:24
453 查看
package com.vanke.easysale.widget.chart; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import com.vanke.IntegratedPlatform.manager.R; import com.vanke.easysale.util.DensityUtil; import com.vanke.easysale.util.TimeUtils; import java.util.ArrayList; /** * Created by rantao on 2017/8/23. * 折线图+柱状图 */ public class LineBarChartView extends View { private int width; // 控件总宽 private int height; // 控件总高 private int barWidth; // 柱状图宽度 private Paint paint; // 画笔 private String[] xTitles = new String[]{}; // x轴数据 private int[] yDatasForBar = new int[]{}; // 柱状图数据源 private int[] xDatasForBar = new int[]{}; // 折线图数据源 private int TEXTSIZE = 30; private int textSize = 20; private int bottomForChart; // 图表底部坐标 private int maxValue = 0; // 最大值 private int minValue = Integer.MAX_VALUE; // 最小值 private int yTextHeight; // x轴文字高度 private int yMinDefaultDistance = DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_10dp)); // y轴最小值默认高度 private ArrayList<LinePoint> linePoints = new ArrayList<>(); // 柱子集合 private OnBarItemClickListener onBarItemClickListener; // 点击监听 private int defaultHighLightPosition = Integer.MAX_VALUE; // 选中高亮的索引下标 private int timeType = 1; // 时间维度类型(1:本年;2:今日;3:本周;4:本月;5:本季) private boolean isAllZero = false; // 是否全部数据都为0 public LineBarChartView(Context context) { super(context); } public LineBarChartView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public void setxTitles(String[] xTitles) { this.xTitles = xTitles; } public void setTimeType(int timeType) { this.timeType = timeType; initHighLightAccordingToTimeType(); invalidate(); } public void setAllZero(boolean allZero) { isAllZero = allZero; invalidate(); } public void setOnBarItemClickListener(OnBarItemClickListener onBarItemClickListener) { this.onBarItemClickListener = onBarItemClickListener; } public void setyDatasForBar(int[] yDatasForBar) { this.yDatasForBar = yDatasForBar; } public void setxDatasForBar(int[] xDatasForBar) { this.xDatasForBar = xDatasForBar; } public int getBarWidth() { return barWidth; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); updateDimensions(w, h); } /** * 根据时间维度初始化高亮位置 */ private void initHighLightAccordingToTimeType() { switch (timeType) { case 1: // 今日 defaultHighLightPosition = TimeUtils.getCurrentHour() - 1; break; case 2: // 本周 defaultHighLightPosition = TimeUtils.getCurrentWeekDay() - 1; break; case 3: // 本月 defaultHighLightPosition = TimeUtils.getCurrentDay() - 1; break; case 4: // 本季 defaultHighLightPosition = TimeUtils.getCurrentSeason() - 1; break; case 5: // 本年 defaultHighLightPosition = TimeUtils.getCurrentMonth() - 1; break; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); barWidth = width / xTitles.length; bottomForChart = height - DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_7dp)); floatX = barWidth * defaultHighLightPosition; floatY = height / 2; drawXAsix(canvas); drawBar(canvas); drawLine(canvas); drawFloat(canvas); } private boolean hasData(int[] datas) { boolean hasData = false; for (int i = 0; i < datas.length; i++) { if (datas[i] != 0) { hasData = true; } } return hasData; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = measure(widthMeasureSpec); int height = measure(heightMeasureSpec); setMeasuredDimension(width, height); updateDimensions(width, height); } private void init(Context context, AttributeSet attrs) { setLayerType(LAYER_TYPE_SOFTWARE, paint);// 屏蔽掉,阴影不显示,不屏蔽,ondraw方法执行无数次 paint = new Paint(); paint.setAntiAlias(true); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LineBarChartView); for (int i = 0; i < a.length(); i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.LineBarChartView_xAsix_textSize: textSize = (int) a.getDimension(attr, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, TEXTSIZE, getResources().getDisplayMetrics())); break; default: break; } } a.recycle(); } /** * 绘制文本 * * @param canvas 画布 * @param text 文本 * @param left 坐标 * @param top * @param right * @param bottom * @param color 文字颜色 */ private void drawText(Canvas canvas, String text, int left, int top, int right, int bottom, int color) { Rect rect = new Rect(left, top, right, bottom); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(textSize); paint.setColor(color); paint.setShadowLayer(0, 0, 0, ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawText(text, rect.centerX(), baseline, paint); } /** * 绘制x轴 * * @param canvas */ private void drawXAsix(Canvas canvas) { paint.setStyle(Paint.Style.FILL); paint.setFakeBoldText(false); paint.setAntiAlias(true); // 绘制X轴数据 for (int i = 0; i < xTitles.length; i++) { int left = (i) * barWidth; int right = (i + 1) * (barWidth); int top = height - DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_5dp)); int bottom = height; Rect rect = new Rect(left, top, right, bottom); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(textSize); paint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); if (timeType == 1 || timeType == 3) { // 时间维度是今日或者是本月,当x轴数据大于10时,需要间隔一个绘制X轴刻度数据 if (i > 9) { if (i % 2 == 1) { drawText(canvas, xTitles[i], left, top, right, bottom, ContextCompat.getColor(getContext(), R.color.color_666666)); } } else { // canvas.drawText(xTitles[i], rect.centerX(), baseline, paint); drawText(canvas, xTitles[i], left, top, right, bottom, ContextCompat.getColor(getContext(), R.color.color_666666)); } } else { // canvas.drawText(xTitles[i], rect.centerX(), baseline, paint); drawText(canvas, xTitles[i], left, top, right, bottom, ContextCompat.getColor(getContext(), R.color.color_666666)); } Paint.FontMetrics fr = paint.getFontMetrics(); //ceil() 函数向上舍入为最接近的整数 yTextHeight = (int) Math.ceil(fr.descent - fr.ascent); bottomForChart = height - yTextHeight - DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_2dp)); } // 绘制X轴刻度线 for (int i = 0; i <= xTitles.length; i++) { int startX = i * barWidth; int endX = startX; int startY = height - yTextHeight - DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_2dp)); int endY = height - yTextHeight; paint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); paint.setStrokeWidth(1f); canvas.drawLine(startX, startY, endX, endY, paint); } // 绘制X轴 int startX = 0; int endX = width; int startY = bottomForChart; int endY = startY; paint.setStrokeWidth(1f); paint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); canvas.drawLine(startX, startY, endX, endY, paint); } /** * 绘制柱状图 * * @param canvas */ private void drawBar(Canvas canvas) { paint.setStyle(Paint.Style.FILL); if (null != linePoints && linePoints.size() > 0) { linePoints.clear(); } for (int i = 0; i < yDatasForBar.length; i++) { if (yDatasForBar[i] > maxValue) { maxValue = yDatasForBar[i]; } if (yDatasForBar[i] < minValue) { minValue = yDatasForBar[i]; } } for (int i = 0; i < xDatasForBar.length; i++) { if (xDatasForBar[i] > maxValue) { maxValue = xDatasForBar[i]; } if (xDatasForBar[i] < minValue) { minValue = xDatasForBar[i]; } } paint.setAlpha(230); for (int i = 0; i < yDatasForBar.length; i++) { // 记录所有柱状图位置 LinePoint point = new LinePoint(); float ratio = (float) (yDatasForBar[i] - minValue) / (float) (maxValue - minValue); int left = i * barWidth + DensityUtil.dip2px(getContext(), 1.5f); int right = (i + 1) * barWidth - DensityUtil.dip2px(getContext(), 1.5f); int bottom = bottomForChart; int top = (int) (bottomForChart * (1 - ratio)); if (!isAllZero) { if (ratio == 0) { if (yDatasForBar[i] > 0) { // 最小值不为0 top = bottomForChart - yMinDefaultDistance; } else { point.zero = true; } } else if (ratio == 1) { top = top - yMinDefaultDistance; } } else { top = bottomForChart; } paint.setColor(ContextCompat.getColor(getContext(), R.color.color_red)); Rect rect = new Rect(left, top, right, bottom); if (defaultHighLightPosition == i) { paint.setColor(ContextCompat.getColor(getContext(), R.color.color_ffd633)); } // 只绘制非0部分 // if (yDatasForBar[i] != 0) { paint.setShadowLayer(0, 0, 0, ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawRect(rect, paint); // } point.minX = left; point.maxX = right; point.minY = top; point.maxY = bottom; linePoints.add(point); } paint.setAlpha(255); } /** * 绘制折线图 * * @param canvas */ private void drawLine(Canvas canvas) { paint.setStyle(Paint.Style.FILL); for (int i = 0; i < yDatasForBar.length; i++) { if (yDatasForBar[i] > maxValue) { maxValue = yDatasForBar[i]; } if (yDatasForBar[i] < minValue) { minValue = yDatasForBar[i]; } } for (int i = 0; i < xDatasForBar.length; i++) { if (xDatasForBar[i] > maxValue) { maxValue = xDatasForBar[i]; } if (xDatasForBar[i] < minValue) { minValue = xDatasForBar[i]; } } for (int i = 0; i < xDatasForBar.length; i++) { if (i != xDatasForBar.length - 1) { paint.setColor(getResources().getColor(R.color.color_ffd633)); paint.setStrokeWidth(4); int startX = (2 * (i + 1) - 1) * barWidth / 2; float ratio = (float) (xDatasForBar[i] - minValue) / (float) (maxValue - minValue); int startY = (int) (bottomForChart * (1 - ratio)); if (!isAllZero) { if (ratio == 0) { if (xDatasForBar[i] > 0) { startY = bottomForChart - yMinDefaultDistance; } } else if (ratio == 1) { startY = startY + DensityUtil.dip2px(getContext(), 20); } } else { startY = bottomForChart; } ratio = (float) (xDatasForBar[i + 1] - minValue) / (float) (maxValue - minValue); int endX = (2 * (i + 2) - 1) * barWidth / 2; int endY = (int) (bottomForChart * (1 - ratio)); if (!isAllZero) { if (ratio == 0) { if (xDatasForBar[i + 1] > 0) { endY = bottomForChart - yMinDefaultDistance; } } else if (ratio == 1) { endY = endY + DensityUtil.dip2px(getContext(), 20); } } else { endY = bottomForChart; } paint.setShadowLayer(getResources().getDimensionPixelOffset(R.dimen.dimen_1dp), getResources().getDimensionPixelOffset(R.dimen.dimen_1dp), getResources().getDimensionPixelOffset(R.dimen.dimen_2dp), ContextCompat.getColor(getContext(), R.color.color_999999)); // 绘制阴影代码 paint.setStrokeWidth(getResources().getDimension(R.dimen.dimen_2dp)); canvas.drawLine(startX, startY, endX, endY, paint); if (defaultHighLightPosition != i) { paint.setColor(getResources().getColor(R.color.color_ffd633)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_4dp), paint); paint.setShadowLayer(0, 0, 0, ContextCompat.getColor(getContext(), R.color.color_333333)); paint.setColor(getResources().getColor(R.color.white)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_2dp), paint); } else { paint.setColor(getResources().getColor(R.color.color_ffd633)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_8dp), paint); paint.setShadowLayer(0, 0, 0, ContextCompat.getColor(getContext(), R.color.color_333333)); paint.setColor(getResources().getColor(R.color.white)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_4dp), paint); } } else { int bottom = bottomForChart; int startX = (2 * (i + 1) - 1) * barWidth / 2; float ratio = (float) (xDatasForBar[i] - minValue) / (float) (maxValue - minValue); int startY = (int) (bottom * (1 - ratio)); if (!isAllZero) { if (ratio == 0) { if (xDatasForBar[i] > 0) { startY = bottomForChart - yMinDefaultDistance; } } else if (ratio == 1) { startY = startY - DensityUtil.dip2px(getContext(), getResources().getDimension(R.dimen.dimen_10dp)); } } else { startY = bottomForChart; } if (defaultHighLightPosition != i) { paint.setColor(getResources().getColor(R.color.color_ffd633)); paint.setShadowLayer(getResources().getDimension(R.dimen.dimen_3dp), getResources().getDimension(R.dimen.dimen_1dp), getResources().getDimension(R.dimen.dimen_1dp), ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_5dp), paint); paint.setColor(getResources().getColor(R.color.white)); paint.setShadowLayer(0, 0, 0, ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_3dp), paint); } else { paint.setColor(getResources().getColor(R.color.color_ffd633)); paint.setShadowLayer(getResources().getDimension(R.dimen.dimen_3dp), getResources().getDimension(R.dimen.dimen_1dp), getResources().getDimension(R.dimen.dimen_1dp), ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_8dp), paint); paint.setColor(getResources().getColor(R.color.white)); paint.setShadowLayer(0, 0, 0, R.color.color_333333); canvas.drawCircle(startX, startY, getResources().getDimension(R.dimen.dimen_5dp), paint); } } } } int floatX; int floatY; /** * 绘制浮层 * * @param canvas 画布 */ private void drawFloat(Canvas canvas) { String currentMonth = ""; String lastTip = ""; String currentTip = ""; switch (timeType) { case 1: lastTip = "今日"; currentTip = "昨日"; currentMonth = (defaultHighLightPosition + 1)+ "时"; break; case 2: lastTip = "本周"; currentTip = "上周"; currentMonth = "周" + (defaultHighLightPosition + 1); break; case 3: lastTip = "本月"; currentTip = "上月"; currentMonth = (defaultHighLightPosition +1) + "号"; break; case 4: lastTip = "本季"; currentTip = "上季"; currentMonth = (defaultHighLightPosition + 1) + "月"; break; case 5: lastTip = "今年"; currentTip = "去年"; currentMonth = (defaultHighLightPosition + 1) + "月"; break; default: break; } // paint.setAlpha(10); // paint.setShadowLayer(getResources().getDimension(R.dimen.dimen_3dp), // getResources().getDimension(R.dimen.dimen_2dp), getResources().getDimension(R.dimen.dimen_2dp), ContextCompat.getColor(getContext(), R.color.color_333333)); // 绘制圆角矩形 int rectLeft = floatX - getResources().getDimensionPixelOffset(R.dimen.dimen_45dp); int rectTop = floatY - getResources().getDimensionPixelOffset(R.dimen.dimen_25dp); int rectRight = floatX + getResources().getDimensionPixelOffset(R.dimen.dimen_45dp); int rectBottom = floatY + getResources().getDimensionPixelOffset(R.dimen.dimen_25dp); if (rectLeft <= 0) { rectLeft = 0; rectRight = 2 * getResources().getDimensionPixelOffset(R.dimen.dimen_50dp); } if (rectRight >= width) { rectRight = width; rectLeft = width - 2 * getResources().getDimensionPixelOffset(R.dimen.dimen_50dp); } RectF rectF = new RectF(rectLeft, rectTop, rectRight, rectBottom); canvas.saveLayerAlpha(rectF, 204, Canvas.CLIP_TO_LAYER_SAVE_FLAG); paint.setColor(Color.WHITE); canvas.drawRect(rectF, paint); canvas.restore(); paint.setStrokeWidth(getResources().getDimension(R.dimen.dimen_05dp)); paint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); canvas.drawLine(rectLeft, rectTop, rectRight, rectTop, paint); canvas.drawLine(rectRight, rectTop, rectRight, rectBottom, paint); canvas.drawLine(rectRight, rectBottom, rectLeft, rectBottom, paint); canvas.drawLine(rectLeft, rectBottom, rectLeft, rectTop, paint); // Path path = new Path(); // path.moveTo(rectLeft, rectTop); // path.lineTo(rectRight, rectTop); // path.lineTo(rectRight, rectBottom); // path.lineTo(rectLeft, rectBottom); // path.lineTo(rectLeft, rectTop - 5f); // CornerPathEffect pathEffect = new CornerPathEffect(10f); // paint.setPathEffect(pathEffect); // paint.setStyle(Paint.Style.STROKE); // canvas.drawPath(path, paint); paint.setStyle(Paint.Style.FILL); // 绘制月份文本 int monthCenter = (rectLeft + rectRight) / 2; int monthLeft = monthCenter - getResources().getDimensionPixelOffset(R.dimen.dimen_5dp); int monthRight = monthCenter + getResources().getDimensionPixelOffset(R.dimen.dimen_5dp); int monthTop = rectTop + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int monthBottom = monthTop + getResources().getDimensionPixelOffset(R.dimen.dimen_5dp); paint.setTextSize(getResources().getDimensionPixelSize(R.dimen.textsize_10sp)); drawText(canvas, currentMonth, monthLeft, monthTop, monthRight, monthBottom, ContextCompat.getColor(getContext(), R.color.color_666666)); int roundRadius = getResources().getDimensionPixelOffset(R.dimen.dimen_3dp); // 绘制上期数据圆点 int lastRoundCenterX = rectLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int lastRoundCenterY = monthBottom + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); paint.setColor(ContextCompat.getColor(getContext(), R.color.color_ffd633)); canvas.drawCircle(lastRoundCenterX, lastRoundCenterY, roundRadius, paint); // 绘制上期数据提示文本 int lastTipLeft = lastRoundCenterX + roundRadius + getResources().getDimensionPixelOffset(R.dimen.dimen_20dp); int lastTipRight = lastTipLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int lastTipTop = lastRoundCenterY - getResources().getDimensionPixelOffset(R.dimen.dimen_8dp); int lastTipBottom = lastRoundCenterY + getResources().getDimensionPixelOffset(R.dimen.dimen_8dp); drawText(canvas, lastTip, lastTipLeft, lastTipTop, lastTipRight, lastTipBottom, ContextCompat.getColor(getContext(), R.color.color_666666)); // 绘制本期数据圆点 int currentRoundCenterX = rectLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int currentRoundCenterY = lastRoundCenterY + getResources().getDimensionPixelOffset(R.dimen.dimen_15dp); paint.setColor(ContextCompat.getColor(getContext(), R.color.color_red)); canvas.drawCircle(currentRoundCenterX, currentRoundCenterY, roundRadius, paint); // 绘制本期提示数据 int currentTipLeft = currentRoundCenterX + roundRadius + getResources().getDimensionPixelOffset(R.dimen.dimen_20dp); int currentTipRight = currentTipLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int currentTipTop = currentRoundCenterY - getResources().getDimensionPixelOffset(R.dimen.dimen_8dp); int currentTipBottom = currentRoundCenterY + getResources().getDimensionPixelOffset(R.dimen.dimen_8dp); drawText(canvas, currentTip, currentTipLeft, currentTipTop, currentTipRight, currentTipBottom, ContextCompat.getColor(getContext(), R.color.color_666666)); // 绘制上期数据 int lastLineLeft = lastTipRight + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int lastLineRight = lastLineLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_20dp); int lastLineTop = lastTipTop; int lastLineBottom = lastTipBottom; paint.setTypeface(Typeface.DEFAULT_BOLD); try { drawText(canvas, yDatasForBar[defaultHighLightPosition] + "", lastLineLeft, lastLineTop, lastLineRight, lastLineBottom, ContextCompat.getColor(getContext(), R.color.color_666666)); } catch (Exception e) { e.printStackTrace(); } // 绘制本期数据 int currentLineLeft = currentTipRight + getResources().getDimensionPixelOffset(R.dimen.dimen_10dp); int currentLineRight = currentLineLeft + getResources().getDimensionPixelOffset(R.dimen.dimen_20dp); int currentLineTop = currentTipTop; int currentLineBottom = currentTipBottom; try { drawText(canvas, xDatasForBar[defaultHighLightPosition] + "", currentLineLeft, currentLineTop, currentLineRight, currentLineBottom, ContextCompat.getColor(getContext(), R.color.color_666666)); } catch (Exception e) { e.printStackTrace(); } paint.setTypeface(Typeface.DEFAULT); } int downX = 0; // 按下时X坐标 int downY = 0; // 按下时Y坐标 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = (int) event.getX(); downY = (int) event.getY(); break; case MotionEvent.ACTION_UP: int upX = (int) event.getX(); int upY = (int) event.getY(); if (Math.abs(downX - upX) < 10 && Math.abs(downY - upY) < 10) { for (int i = 0; i < linePoints.size(); i++) { LinePoint point = linePoints.get(i); if (upX > point.minX && upX < point.maxX && upY > 0 && upY < height) { if (null != onBarItemClickListener) { onBarItemClickListener.onBarItemClick(i, upX - DensityUtil.dip2px(getContext(), 30), upY); defaultHighLightPosition = i; floatX = upX; floatY = upY; invalidate(); } } } } break; } return true; } private int measure(int measureSpec) { int result = 0; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); switch (mode) { case MeasureSpec.EXACTLY: result = size; break; case MeasureSpec.AT_MOST: result = size; break; case MeasureSpec.UNSPECIFIED: break; default: break; } return result; } private void updateDimensions(int width, int height) { this.width = width; this.height = height; } private class LinePoint { int minX; int maxX; int minY; int maxY; boolean zero = false; // 数据是否为0 } public interface OnBarItemClickListener { void onBarItemClick(int index, int x, int y); } }
相关文章推荐
- Android 借助aChartEngine实现饼图,折线图,柱状图
- Android图表超简单实现柱状图、折线图、饼状图(基于MpAndroidChart)
- Android图表超简单实现柱状图、折线图、饼状图(基于MpAndroidChart)
- Android上实现柱状图表
- JFreeChart实现饼状图、柱状图和折线图以及各类报表
- 实现自定义android柱状图控件!可显示气温!可相应点击事件的回调!
- 插件jfreechart+shh实现树状图 柱状图 折线图
- <Android开发代码库>achartengine实现柱状图、圆饼图、线图等
- [AndroidUI]自定义view(五):实现动态柱状图
- Android 自定义View,实现折线图
- 分组折线图、柱状图实现(多条折线图、柱状图同时显示)实现方式
- Android使用自定义View继承SurfaceView实现动态折线图的绘制
- Android画折线图、柱状图、饼图(使用achartengine.jar)
- PHP实现动态生成饼状图、柱状图和折线图(转载)
- Android上实现柱状图表 可实现边框矩形 没填充色
- android上动态实现ichartjs & highcharts 的绘图 2D 3D 折线图 柱形图 圆形图 等等
- jsp+vml 实现柱状图、饼图、折线图
- Android上实现柱状图表
- (转)Android自定义统计图(柱状图,折线图,饼状图)
- Android上实现柱状图表