注释在代码中:
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Created by wangliang on 0013/2016/9/13. * 思路:每传递一次坐标名称则更新一次视图,坐标的传递采用动态计算的方法,当更改坐标轴名称的时候,所有视图清空进行重绘,柱状图显示数量由所传递的徐州的名称决定 */ public class HistogramNoScrollView extends View { private Context context; private final String TAG = "HistogramNoScrollView"; private Integer defaultAxisColor = Color.BLACK; private Integer defaultAxisWidth; private List<String> xAxisListNames; private List<String> yAxisListNames; private List<Coordinate> xAxisCoordinateList;//所有x轴基准点坐标 private List<Coordinate> yAxisCoordinateList;//所有y轴基准点坐标 private List<Coordinate> xAxisTextCoordinateList;//所有x轴文字坐标 private List<Coordinate> yAxisTextCoordinateList;//所有y轴文字坐标 private List<LineCoordinate> listAllNoAxisCoordinate;//除轴上坐标之外的其他柱状图的坐标 private Paint xAxisTextPaint;//x轴文字画笔 private Paint yAxisTextPaint;//y轴文字画笔 private Paint xAxisPaint;//x轴画笔 private Paint yAxisPaint;//y轴画笔 private Paint histogramPaint;//柱状图画笔 private Paint averageValuePaint;//平均值线 private Path averageValuePath;//平均值线 private Integer axisTextColor; private Integer axisTextSize; private Integer defaultBetweenXAxisAndTextSpace; private Integer defaultBetweenYAxisAndTextSpace; private int xCoordinateDistance;//x轴每段的宽度 private Double maxValue;//柱状图所能显示的最大值 private Double averageValue;//柱状图的平均值 private Map<String,Double> histogramValue;//柱状图所哟柱子的值 private float histogramShowFanWei;//柱状图所能显示的范围 private Boolean whetherShowXAxis;//是否显示y轴 private Boolean whetherShowYAxis;//是否显示x轴 private Boolean whetherShowAverageValue;//是否显示柱状图平均值 public HistogramNoScrollView(Context context) { super(context); initSetting(context,null); } public HistogramNoScrollView(Context context, AttributeSet attrs) { super(context, attrs); initSetting(context,null); } public HistogramNoScrollView(Context context, AttributeSet attrs, Integer defStyleAttr) { super(context, attrs, defStyleAttr); initSetting(context,defStyleAttr); } private void initSetting(Context context, Integer defStyleAttr) { this.context = context; defaultBetweenXAxisAndTextSpace = 0; defaultBetweenYAxisAndTextSpace = 0; defaultAxisColor = Color.BLACK; defaultAxisWidth = context.getResources().getDimensionPixelOffset(R.dimen.common_dp_0_2); axisTextColor = Color.RED; axisTextSize = context.getResources().getDimensionPixelOffset(R.dimen.default_text_medium); xAxisTextPaint = new Paint(); xAxisTextPaint.setTextSize(axisTextSize); xAxisTextPaint.setColor(axisTextColor); yAxisTextPaint = new Paint(); yAxisTextPaint.setTextSize(axisTextSize); yAxisTextPaint.setColor(axisTextColor); xAxisPaint = new Paint(); xAxisPaint.setColor(defaultAxisColor); xAxisPaint.setStrokeWidth(defaultAxisWidth); yAxisPaint = new Paint(); yAxisPaint.setColor(defaultAxisColor); yAxisPaint.setStrokeWidth(defaultAxisWidth); averageValuePaint = new Paint ( ) ; averageValuePaint.setColor ( Color.BLACK ) ; //设置画直线格式 averageValuePaint.setStyle ( Paint.Style.STROKE ) ; /**设置虚线效果 * 里边的float数组的意思是:先画长度为3的实线,再间隔长度为2的空白,之后一直重复这个单元。 * 这个数组的长度只要大于等于2就行,你可以设置多个数值,产生不同效果,最后这个0指的是与起始位置的偏移量。 */ averageValuePaint.setPathEffect ( new DashPathEffect( new float [ ] { 3, 2 }, 0 ) ) ; } /** * 设置x轴坐标文字 * @param xAxisListNames * @return */ public HistogramNoScrollView setXAxisNames(List<String> xAxisListNames,boolean whetherShowXAxis){ this.xAxisListNames = xAxisListNames; this.whetherShowXAxis = whetherShowXAxis; return this; } /** * 设置y轴坐标文字 * @param yAxisListNames * @return */ public HistogramNoScrollView setYAxisNames(List<String> yAxisListNames,boolean whetherShowYAxis){ this.yAxisListNames = yAxisListNames; this.whetherShowYAxis = whetherShowYAxis; return this; } /** * 设置柱状图所要显示的最大值以及平均值 * @param maxValue 最大值 * @param averageValue 平均值 * @param whetherShowAverageValue 是否显示平均值线 * @return */ public HistogramNoScrollView setMaxValueAndAverageValue(double maxValue,double averageValue,boolean whetherShowAverageValue){ this.maxValue = maxValue; this.averageValue = averageValue; this.whetherShowAverageValue = whetherShowAverageValue; return this; } public HistogramNoScrollView setHistogramValue(Map<String,Double> histogramValue){ this.histogramValue = histogramValue; return this; } @Override protected void onDraw(Canvas canvas) { if(xAxisTextCoordinateList == null){ getXAxisTextCoordinateList(); } if(xAxisCoordinateList == null){ getXAxisCoordinateList(); } if(yAxisTextCoordinateList == null){ getYAxisTextCoordinateList(); } if(yAxisCoordinateList == null){ getYAxisCoordinateList(); } if(listAllNoAxisCoordinate == null){ getListAllNoAxisCoordinate(); } /** * 获取所要画的虚线的path */ if(averageValuePath == null && maxValue != null && averageValue != null){ histogramShowFanWei = getHeight() - (fm.descent - fm.ascent) - defaultBetweenXAxisAndTextSpace; averageValuePath = new Path(); averageValuePath.moveTo(0, (float) (histogramShowFanWei - histogramShowFanWei * (averageValue / maxValue))); averageValuePath.lineTo(getWidth() - defaultBetweenYAxisAndTextSpace, (float) (histogramShowFanWei - histogramShowFanWei * (averageValue / maxValue))); } /** * 画x轴 */ if(xAxisTextCoordinateList.size() > 0 && whetherShowXAxis) { canvas.drawLine(getX() - defaultBetweenYAxisAndTextSpace, getHeight() - (fm.descent - fm.ascent) - defaultBetweenXAxisAndTextSpace, getWidth(), getHeight() - (fm.descent - fm.ascent) - defaultBetweenXAxisAndTextSpace , xAxisPaint); } /** * 画y轴 */ if(yAxisTextCoordinateList.size() > 0 && whetherShowYAxis) { canvas.drawLine(getX() - defaultBetweenYAxisAndTextSpace, 0, getX() - defaultBetweenYAxisAndTextSpace, getHeight() - (fm.descent - fm.ascent) - defaultBetweenXAxisAndTextSpace , xAxisPaint); } /** * 画虚线,代表着平均值 */ if(listAllNoAxisCoordinate.size() > 0 && whetherShowAverageValue){ canvas.drawPath(averageValuePath,averageValuePaint); } /** * 绘制x轴上的坐标刻度文字 */ for(int i = 0 ; i < xAxisTextCoordinateList.size() ; i++){ canvas.drawText(xAxisTextCoordinateList.get(i).getCoordinatename(), xAxisTextCoordinateList.get(i).getxCoordinate(), xAxisTextCoordinateList.get(i).getyCoordinate(), xAxisTextPaint); } /** * 绘制柱状图 */ for(int i = 0 ; i < listAllNoAxisCoordinate.size() ; i++){ histogramPaint = new Paint(); histogramPaint.setColor(listAllNoAxisCoordinate.get(i).getColor()); canvas.drawRect(new Rect(Math.round(listAllNoAxisCoordinate.get(i).getxStartCoordinate()) ,Math.round(listAllNoAxisCoordinate.get(i).getyStartCoordinate()) ,Math.round(listAllNoAxisCoordinate.get(i).getxStopCoordinate()) ,Math.round(listAllNoAxisCoordinate.get(i).getyStopCoordinate())) ,histogramPaint); } } private Paint.FontMetrics fm; /** * 根据文字获得文字相对于x轴的坐标 * @param text * @param xCoordinateDistance * @return */ private float[] getXtextCoordinate(String text,float xCoordinateDistance){ float[] xy = new float[2]; fm = xAxisTextPaint.getFontMetrics(); float textWidth = xAxisTextPaint.measureText(text); float textHeight = fm.descent - fm.ascent; xy[0] = xCoordinateDistance - textWidth / 2; xy[1] = getHeight(); return xy; } /** * 获取x轴刻度文字坐标 */ private void getXAxisTextCoordinateList(){ xAxisTextCoordinateList = new ArrayList<>(); if(xAxisListNames != null) { xCoordinateDistance = getWidth() / (xAxisListNames.size() + 1); for (int i = 0; i < xAxisListNames.size(); i++) { float[] xtextCoordinate = getXtextCoordinate(xAxisListNames.get(i), xCoordinateDistance * (i + 1)); xAxisTextCoordinateList.add(new Coordinate(xtextCoordinate[0], xtextCoordinate[1], xAxisListNames.get(i))); } } } /** * 获取x轴线坐标 */ private void getXAxisCoordinateList(){ xAxisCoordinateList = new ArrayList<>(); if(xAxisListNames != null) { fm = xAxisTextPaint.getFontMetrics(); float textHeight = fm.descent - fm.ascent; xCoordinateDistance = getWidth() / (xAxisListNames.size() + 1); for (int i = 0; i < xAxisListNames.size(); i++) { xAxisCoordinateList.add(new Coordinate(getX() + xCoordinateDistance * (i + 1) , getHeight() - textHeight, xAxisListNames.get(i))); } } } /** * 获取y轴刻度文字坐标 */ private void getYAxisTextCoordinateList(){ yAxisTextCoordinateList = new ArrayList<>(); } /** * 获取y轴线坐标 */ private void getYAxisCoordinateList(){ yAxisCoordinateList = new ArrayList<>(); } private void getListAllNoAxisCoordinate(){ listAllNoAxisCoordinate = new ArrayList<>(); histogramShowFanWei = getHeight() - (fm.descent - fm.ascent) - defaultBetweenXAxisAndTextSpace; LineCoordinate lineCoordinate; if(maxValue != null && xAxisListNames != null && xAxisCoordinateList != null){ for(int i = 0 ; i < xAxisListNames.size() ; i++){ lineCoordinate = new LineCoordinate(); lineCoordinate.setxStartCoordinate((float) (xAxisCoordinateList.get(i).getxCoordinate() - xCoordinateDistance * 0.45)); lineCoordinate.setyStartCoordinate((float) (xAxisCoordinateList.get(i).getyCoordinate() - histogramShowFanWei * (histogramValue.get(xAxisListNames.get(i)) / maxValue))); lineCoordinate.setxStopCoordinate((float) (xAxisCoordinateList.get(i).getxCoordinate() + xCoordinateDistance * 0.45)); lineCoordinate.setyStopCoordinate((float) (xAxisCoordinateList.get(i).getyCoordinate())); lineCoordinate.setColor(Color.BLACK); listAllNoAxisCoordinate.add(lineCoordinate); } } } }调用方法:
List<String> list = new ArrayList<>(); list.add("123"); list.add("456"); list.add("789"); list.add("147"); list.add("258"); Map<String,Double> map = new HashMap<>(); map.put(list.get(0),10d); map.put(list.get(1),15d); map.put(list.get(3),7d); ((HistogramNoScrollView)findViewById(R.id.test1)).setXAxisNames(list,true); ((HistogramNoScrollView)findViewById(R.id.test1)).setMaxValueAndAverageValue(20,10,true); ((HistogramNoScrollView)findViewById(R.id.test1)).setHistogramValue(map);坐标类参考:http://blog.csdn.net/cmwly/article/details/49951913