今天做项目需要用到简单的横向的柱状图,上网查了一下,没找到合适的框架,于是决定自己动手写一个自定义View,来实现三种柱状图。
那么先看效果图
横向的柱状图,只有柱子的比例和文字。
纵向的柱状图,加上了坐标轴的绘制。
比例式柱状图,只接受长度为2的数组,会自己判断将长的置于背景。
那么我们看一下这个自定义View的代码:
package com.example.day09;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
/**
* Created by Administrator on 2016/11/3.
*/
public class Histogram extends View {
private int[] nums;
private String[] names;
private int[] colors;
private Context context;
private int max = 0;
private int type;
private int wheretext;
private int maxlong;
private int j;
private int width;
private int kong;
private boolean useAnimation;
private Histogram v;
public void setNames(String[] names) {
this.names = names;
}
public void setMax(int max) {
this.max = max;
}
public void setType(int type) {
this.type = type;
}
public void setWheretext(int wheretext) {
this.wheretext = wheretext;
}
public void setMaxlong(int maxlong) {
this.maxlong = maxlong;
}
public void setWidth(int width) {
this.width = width;
}
public void setKong(int kong) {
this.kong = kong;
}
public void setUseAnimation(boolean useAnimation) {
this.useAnimation = useAnimation;
}
public Histogram(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
v = this;
}
public Histogram(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
v = this;
}
public Histogram(Context context) {
super(context);
v = this;
this.context = context;
}
/**
* 初始化柱状图的方法
*
* @param nums 存放每个元素数量的数组
* @param names 存放每个元素文字的数组
* @param colors 存放每个元素使用的颜色的数组
* @param type 定义柱状图的类型 1为横向,2为纵向,其余为比例
* @param wheretext 定义柱状图文字的位置 (若横向)1为图前,2为图后,其余为无文字;(若纵向)1为图下,其余无文字
* @param maxlong 柱状图的最大长度(px)
* @param max 最大长度对应的数值
* @param width 每条柱子的宽度
* @param kong 柱子之间的空隙宽度
*/
public void SetHistogram(int[] nums, String[] names, int[] colors, int type, int wheretext, int maxlong, int max, int width, int kong, boolean useAnimation) {
this.colors = colors;
this.names = names;
this.nums = nums;
this.type = type;
this.wheretext = wheretext;
this.maxlong = maxlong;
this.max = max;
j = maxlong / max;
this.width = width;
this.kong = kong;
this.useAnimation = useAnimation;
}
public void SetHistogram(int[] nums, int[] colors, int type) {
SetHistogram(nums, null, colors, type, 0, 800, 100, 50, 0, false);
}
public void SetHistogram(int[] nums, int[] colors) {
SetHistogram(nums, colors, 1);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
switch (type) {
case 1:
DrawHeng(canvas, p);
break;
case 2:
DrawShu(canvas, p);
break;
default:
DrawBiLi(canvas, p);
break;
}
}
/**
* 画横向比例柱状图
*
* @param canvas
* @param p
*/
private void DrawBiLi(Canvas canvas, Paint p) {
int i, j;
if (nums[0] > nums[1]) {
i = 0;
j = 1;
} else {
i = 1;
j = 0;
}
int[] numss = new int[]{nums[i], nums[j]};
int[] colorss = new int[]{colors[i], colors[j]};
String[] namess = new String[]{names[i], names[j]};
float bili = (0.0F + numss[0]) / (0.0F + numss[1]);
switch (wheretext) {
case 1:
p.setColor(colorss[0]);
canvas.drawRect(0, 0, maxlong, width, p);
p.setColor(colorss[1]);
canvas.drawRect(0, 0, maxlong / bili, width, p);
//写字
p.setColor(Color.WHITE);
p.setTextSize(width - 10);
p.setTextAlign(Paint.Align.LEFT);
canvas.drawText(namess[0], 10, width, p);
canvas.drawText(namess[1], maxlong / bili + 10, width, p);
if (useAnimation) {
setAnimationHeng();
}
break;
default:
p.setColor(colorss[0]);
canvas.drawRect(0, 0, maxlong, width, p);
p.setColor(colorss[1]);
canvas.drawRect(0, 0, maxlong / bili, width, p);
if (useAnimation) {
setAnimationHeng();
}
break;
}
}
/**
* 画纵向柱状图
*
* @param canvas
* @param p
*/
private void DrawShu(Canvas canvas, Paint p) {
switch (wheretext) {
case 1:
//画坐标轴
p.setStrokeWidth(5);
p.setColor(Color.BLACK);
canvas.drawLine(30, maxlong, nums.length * (width + kong) + 150, maxlong, p);
canvas.drawLine(nums.length * (width + kong) + 150, maxlong, nums.length * (width + kong) + 120, maxlong - 30, p);
canvas.drawLine(nums.length * (width + kong) + 150, maxlong, nums.length * (width + kong) + 120, maxlong + 30, p);
canvas.drawLine(30, maxlong, 30, 0, p);
canvas.drawLine(30, 0, 0, 30, p);
canvas.drawLine(30, 0, 60, 30, p);
//画柱子
for (int i = 0; i < nums.length; i++) {
p.setColor(colors[i]);
canvas.drawRect(60 + kong + (i * (kong + width)), maxlong - (j * nums[i]), 60 + kong + (i * (kong + width)) + width, maxlong, p);
p.setColor(Color.BLACK);
p.setTextSize(width - 10);
p.setTextAlign(Paint.Align.LEFT);
canvas.drawText(names[i], 60 + ((width + kong) * i) + width / 4, maxlong + width, p);
}
if (useAnimation) {
setAnimationShu();
}
break;
default:
//画坐标轴
p.setStrokeWidth(5);
p.setColor(Color.BLACK);
canvas.drawLine(30, maxlong, nums.length * (width + kong) + 150, maxlong, p);
canvas.drawLine(nums.length * (width + kong) + 150, maxlong, nums.length * (width + kong) + 120, maxlong - 30, p);
canvas.drawLine(nums.length * (width + kong) + 150, maxlong, nums.length * (width + kong) + 120, maxlong + 30, p);
canvas.drawLine(30, maxlong, 30, 0, p);
canvas.drawLine(30, 0, 0, 30, p);
canvas.drawLine(30, 0, 60, 30, p);
//画柱子
for (int i = 0; i < nums.length; i++) {
p.setColor(colors[i]);
canvas.drawRect(60 + kong + (i * (kong + width)), maxlong - (j * nums[i]), 60 + kong + (i * (kong + width)) + width, maxlong, p);
}
if (useAnimation) {
setAnimationShu();
}
break;
}
}
/**
* 画横向柱状图
*
* @param canvas
* @param p
*/
private void DrawHeng(Canvas canvas, Paint p) {
switch (wheretext) {
case 1:
for (int i = 0; i < nums.length; i++) {
p.setColor(Color.BLACK);
p.setTextSize(width - 10);
p.setTextAlign(Paint.Align.RIGHT);
canvas.drawText(names[i], 80, width + width * i, p);
p.setColor(colors[i]);
canvas.drawRect(100, i * width + kong, 100 + nums[i] * j, width + i * width, p);
if (useAnimation) {
setAnimationHeng();
}
}
break;
case 2:
for (int i = 0; i < nums.length; i++) {
p.setColor(colors[i]);
canvas.drawRect(0, i * width + kong, nums[i] * j, width + i * width, p);
p.setColor(Color.BLACK);
p.setTextSize(width - 10);
p.setTextAlign(Paint.Align.LEFT);
canvas.drawText(names[i], nums[i] * j + 20, width + width * i, p);
if (useAnimation) {
setAnimationHeng();
}
}
break;
default:
for (int i = 0; i < nums.length; i++) {
p.setColor(colors[i]);
canvas.drawRect(0, i * width + kong, nums[i] * j, width + i * width, p);
if (useAnimation) {
setAnimationHeng();
}
}
break;
}
}
/**
* 设置动画(横向)
*/
private void setAnimationHeng() {
ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.0f, 1.0f, 1.0f
, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
scaleAnimation.setDuration(1000);
this.setAnimation(scaleAnimation);
scaleAnimation.startNow();
}
/**
* 设置动画(横向)
*/
private void setAnimationShu() {
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f
, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
scaleAnimation.setDuration(1000);
this.setAnimation(scaleAnimation);
scaleAnimation.startNow();
}
}
其中,设置所有参数的方法为
/**
* 初始化柱状图的方法
*
* @param nums 存放每个元素数量的数组
* @param names 存放每个元素文字的数组
* @param colors 存放每个元素使用的颜色的数组
* @param type 定义柱状图的类型 1为横向,2为纵向,其余为比例
* @param wheretext 定义柱状图文字的位置 (若横向)1为图前,2为图后,其余为无文字;(若纵向)1为图下,其余无文字
* @param maxlong 柱状图的最大长度(px)
* @param max 最大长度对应的数值
* @param width 每条柱子的宽度
* @param kong 柱子之间的空隙宽度
*/
public void SetHistogram(int[] nums, String[] names, int[] colors, int type, int wheretext, int maxlong, int max, int width, int kong, boolean useAnimation) {
this.colors = colors;
this.names = names;
this.nums = nums;
this.type = type;
this.wheretext = wheretext;
this.maxlong = maxlong;
this.max = max;
j = maxlong / max;
this.width = width;
this.kong = kong;
this.useAnimation = useAnimation;
}
后面的代码都是根据这个方法传进来的参数做出相应的绘制,当然,大多数有用的属性也单独提供了Set方法;
接下来我们简单的试验一下一个纵向的柱状图,代码如下:
MainActivity:
package com.example.day09;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
public class MainActivity extends Activity {
Histogram histogram;
int[] nums;
int[] colors;
String[] names;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
histogram= (Histogram) findViewById(R.id.imageId);
nums=new int[]{55,24,64,35,100};
colors=new int[]{Color.BLUE,Color.YELLOW,0Xffabcdef,Color.GREEN,Color.RED};
names=new String[]{"A","B","C","D","E"};
histogram.SetHistogram(nums,names,colors,2,1,1000,100,80,10,false);
ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.0f, 1.0f, 1.0f
, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
scaleAnimation.setDuration(1000);
histogram.setAnimation(scaleAnimation);
scaleAnimation.startNow();
scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
histogram.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<com.example.day09.Histogram
android:id="@+id/imageId"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:visibility="invisible" />
</RelativeLayout>
这样就做出了一个简单的柱状图了,截图效果: