本文实例为大家分享了Android自定义圆角柱状图的具体代码,供大家参考,具体内容如下
需求:画一个圆角柱状图,显示12个月的数据,Y轴数据动态分割,如果是当前月,就画出当前月图片;点击柱状图变色,并显示虚线弹出当前月信息,滑动时弹框和虚线消失,柱状图刷新到最初。
1.HistogramRound
package com.broker.liming.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
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.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.broker.liming.R;
import com.broker.liming.bean.ChartData;
import com.broker.liming.utils.ArithUtil;
import com.broker.liming.utils.LogUtil2;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
/**
* @author chenhuirong
* @Date 2018/12/10
* @Description zhu
*/
public class HistogramRound extends ChartYdate {
private int[] rect_color;
private int rect_text_color;//矩形文字颜色
private int rect_big_text_color;//矩形最大文字颜色
private int rect_text_size;//矩形文字尺寸
private getNumberListener listener;
private int selectIndex = -1;
private int yHeightSelect=0;
private int leftSelector=0;
private boolean isScrollow;//true 滑动 false点击
private List<Integer> selectIndexRoles = new ArrayList<>();
private List<Object> objects=new ArrayList<>();
public HistogramRound(Context context) {
super(context);
}
public HistogramRound(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initStyle(context,attrs);
}
public HistogramRound(Context context, AttributeSet attrs) {
super(context, attrs);
initStyle(context,attrs);
}
/*
* 初始化样式属性
*/
private void initStyle(Context context,AttributeSet attrs) {
TypedArray types = context.obtainStyledAttributes(attrs, R.styleable.zqxchart_histogram);
coordinates_color = types.getColor(R.styleable.zqxchart_histogram_hCoordinatesColor, Color.RED);
rect_text_color = types.getColor(R.styleable.zqxchart_histogram_rectTextColor,Color.BLACK);
rect_big_text_color=getResources().getColor(R.color.text_yellow);
rect_text_size = types.getInteger(R.styleable.zqxchart_histogram_rectTextSize,28);
x_text_color = types.getColor(R.styleable.zqxchart_histogram_hxTextColor,Color.BLACK);
y_text_color = types.getColor(R.styleable.zqxchart_histogram_hyTextColor,Color.BLACK);
x_text_size = types.getInteger(R.styleable.zqxchart_histogram_hxTextSize,30);
y_text_size = types.getInteger(R.styleable.zqxchart_histogram_hyTextSize,28);
xpCount = types.getInteger(R.styleable.zqxchart_histogram_hxPointCount,12);
ypCount = types.getInteger(R.styleable.zqxchart_histogram_hyPointCount,12);
rect_color = getResources().getIntArray(R.array.histogram_color);
animType = types.getInteger(R.styleable.zqxchart_histogram_hanimType, Anim.ANIM_NONE);
types.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (xData!=null&&yData!=null){
drawHistogramRound(canvas);
}
}
/*
* 画柱状图
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void drawHistogramRound(Canvas canvas) {
//如果没有设置x轴数据
if (xData == null){
throw new NullPointerException("x轴数据源不能为空!");
}
//如果没有设置y轴数据
if (yData == null){
throw new NullPointerException("y轴数据源不能为空!");
}
Paint histogramPaint = new Paint();
// histogramPaint.setAntiAlias(true);
histogramPaint.setStyle(Paint.Style.FILL);
histogramPaint.setStrokeWidth((float) 4.0);
histogramPaint.setStrokeCap(Paint.Cap.ROUND);
//矩形上具体数据画笔
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// tv_mudi.setTextSize(TypedValue.COMPLEX_UNIT_PX,getResources().getDimension(R.dimen.font_13));
// textPaint.setTextSize(rect_text_size);
Paint mPaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
// mPaintCircle.setStyle(Paint.Style.ANTI_ALIAS_FLAG);
//
mPaintCircle.setStrokeWidth(2);
mPaintCircle.setColor(Color.parseColor("#ff5932"));
mPaintCircle.setPathEffect(new DashPathEffect(new float[]{4, 4}, 0));
mPaintCircle.setAntiAlias(true);
textPaint.setTextSize(getResources().getDimension(R.dimen.font_9));
DecimalFormat formater = new DecimalFormat("0.000");
for (int i=0; i<xpCount; i++){
try {
histogramPaint.setColor(rect_color == null
? getResources().getColor(R.color.colorPrimary)
: rect_color[i]);
}catch (ArrayIndexOutOfBoundsException e){
histogramPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
int alpha = anims[i].getAlpha();
textPaint.setAlpha(alpha);
histogramPaint.setAlpha(alpha);
//计算执行动画当前y坐标
float top = anims[i].getCurrentY();
float left = oX+xCoordinates[i]-xSpacing/5;
float right = oX+xCoordinates[i]+xSpacing/3;
String a = formater.format(yData[i]);
String ydata=a.substring(0,a.indexOf("."));
int[] textSize = getTextSize(xData[i],textPaint);
float textY = top - textSize[1]/2;
LogUtil2.log("yMax-------"+yMax+"--ydata--"+ydata);
if (Float.valueOf(ydata)>=yMax){
textPaint.setColor(rect_big_text_color);
}else {
textPaint.setColor(rect_text_color);
}
LogUtil2.log("yData--------------->ydataY轴上的数据"+ydata);
//画矩形上文字
// canvas.drawText(ydata,left+20,textY,textPaint);
//计算每条柱状图的宽度
// double tempBarWidth = (((int) mXinterval) >> 1) / mCategoryList.size();
// mBarPaint.setStrokeWidth((float) tempBarWidth);
if (selectIndex==i){
histogramPaint.setColor(ContextCompat.getColor(getContext(), R.color.name_ffa646));
//draw x 坐标
yHeightSelect= (int) top/*-getPaddingTop() */- getPaddingBottom()-xTextSurplus-x_text_size;
yHeightSelect= (int) (/*(oY+75)-(*/top/*+getPaddingTop()/)*/);
leftSelector= (int) (left+(right-left)/2);
// canvas.drawLine(oX,top, oX,top-yHeight,mPaintCircle);
Path path = new Path();
path.moveTo(oX, oX+xWidth+40);
path.lineTo(oX, oX+xWidth+40);
// canvas.drawPath(path, mPaintCircle);
// canvas.drawLine(oX,top,oX+xWidth+40,top,mPaintCircle);
if (!isScrollow){
listener.getNumber(i, (int) oY, leftSelector,yHeightSelect, (int) oX);
}
LogUtil2.log("setSelect--画:--getHeight"+getHeight()+"--left--"+left+"--height--"+yHeightSelect+"--top--"+top+"--oy--"+oY);
}else {
histogramPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_1FA6FB));
}
//画每一个矩形
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
//画圆角柱只在5.0以上版本适用,以下版本会闪退
canvas.drawRoundRect(left,top,right,oY,30,30,histogramPaint);
}else {
canvas.drawRect(left,top,right,oY,histogramPaint);
}
objects.add(histogramPaint);
}
}
public void setPublicRefresh(){
selectIndex=-1;
invalidate();
for (int i=0;i<objects.size();i++){
Paint paint= (Paint) objects.get(i);
paint.setColor(ContextCompat.getColor(getContext(), R.color.color_1FA6FB));
LogUtil2.log("柱子--"+paint);
}
}
// public void isScrollow(boolean isScrollowt){
// this.isScrollow=isScrollowt;
// };
/*
* 设置数据
*/
@Override
public void setChartYdateData(ChartData chartData) {
super.setChartYdateData(chartData);
HistogramData histogramData = (HistogramData) chartData;
this.rect_color = histogramData.getRectColor() != null ?
histogramData.getRectColor() : this.rect_color;
this.rect_text_size = getFinalValue(this.rect_text_size,histogramData.getRectTextSize());
this.rect_text_color = getFinalValue(this.rect_text_color,histogramData.getRectTextColor());
}
@Override
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
super.setOnLongClickListener(l);
LogUtil2.log("onDraw--getX---弹框的长按事件:" + isScrollow);
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
LogUtil2.log("onDraw--getX---弹框的滑动事件:" + isScrollow);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
LogUtil2.log("onDraw--getX---弹框的滑动改变事件:" + isScrollow);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int x =0;
int y =0;
int left = getPaddingLeft()+yTextSurplus;
int top = 0;
int right = xWidth/ 12+getPaddingLeft()+yTextSurplus;
int bottom = yHeight;
// int right = getWidth()/ 12;
// int bottom = yHeight;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
x = (int) ev.getX();
y = (int) ev.getY();
LogUtil2.log("setSelect--666down--x" + x + "--left--" + y + "ev--x" + ev.getX() + "ev--y" + ev.getY());
// if (isScrollow) {
/* for (int i = 0; i < 12; i++) {
Rect rect = new Rect(left, top, right, bottom);
left += xWidth / 12;
right += xWidth / 12;
if (rect.contains(x, y)) {
if (listener != null) {
LogUtil2.log("setSelect--666down--x" + x + "--left--" + y + "ev--x" + ev.getX() + "ev--y" + ev.getY());
//抬起坐标减去放下坐标绝对值小于20代表点击,否则代表滑动
// if (Math.abs(ArithUtil.sub(ev.getX(), x)) <= 20 && Math.abs(ArithUtil.sub(ev.getY(), y)) <= 20) {
selectIndex = i;
selectIndexRoles.clear();
selectIndexRoles.add(selectIndex);
invalidate();
// }
}
}
}*/
// }
break;
case MotionEvent.ACTION_MOVE:
isScrollow=true;
LogUtil2.log("setSelect--666Move--x" + x + "--left--" + y + "ev--x" + ev.getX() + "ev--y" + ev.getY());
break;
case MotionEvent.ACTION_UP:
isScrollow=false;
x = (int) ev.getX();
y = (int) ev.getY();
LogUtil2.log("setSelect--666UP--x" + x + "--left--" + y + "ev--x" + ev.getX() + "ev--y" + ev.getY());
for (int i = 0; i < 12; i++) {
Rect rect = new Rect(left, top, right, bottom);
left += xWidth / 12;
right += xWidth / 12;
if (rect.contains(x, y)) {
if (listener != null) {
//抬起坐标减去放下坐标绝对值小于20代表点击,否则代表滑动
// if (Math.abs(ArithUtil.sub(ev.getX(), x)) <= 20 && Math.abs(ArithUtil.sub(ev.getY(), y)) <= 20) {
selectIndex = i;
selectIndexRoles.clear();
selectIndexRoles.add(selectIndex);
invalidate();
// }
}
}
}
break;
}
return true;
}
public void setListener(getNumberListener listener) {
this.listener = listener;
}
public interface getNumberListener {
void getNumber(int number, int x, int y,int HeightSelect,int ox);
}
}
2.ChartYdate
package com.broker.liming.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.broker.liming.R;
import com.broker.liming.bean.ChartData;
import com.broker.liming.utils.DensityUtil;
import com.broker.liming.utils.DoubleUtils;
import com.broker.liming.utils.LogUtil2;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author chenhuirong
* @Date 2018/12/10
* @Description 统计图
*
* */
public class ChartYdate extends View {
protected final int xSurplus = 0;//x轴留余
protected final int ySurplus = 20;//y轴留余
protected final int xTextSurplus = 150;//x轴文字留余
protected final int yTextSurplus = 100;//y轴文字留余
protected float oX;//原点x
protected float oY;//原点y
protected int xWidth;//x轴宽度
protected int yHeight;//y轴高度
protected int xSpacing;//x轴坐标间距
protected int ySpacing;//y轴坐标间距
protected int xpCount = 7;//x轴坐标点数
protected int ypCount = 7;//y轴坐标点数
protected int[] xCoordinates;//x轴坐标点
protected int[] yCoordinates;//y轴坐标点
protected float yMax = 0f;//y轴最大刻度值
protected String[] xData;//x轴数据
protected float[] yData;//y轴数据
protected int coordinates_color;//坐标系颜色
protected int x_text_size;//x轴文字尺寸
protected int y_text_size;//y轴文字尺寸
protected int x_text_color;//x轴文字颜色
protected int y_text_color;//y轴文字颜色
protected boolean isAnim = true;
protected Anim[] anims;//动画数组
protected long interval = 100;//动画执行间隔
protected int animType = -2;//动画
private Paint mTableValuePaint;
// private getNumberListener listener;
// private int selectIndex = -1;
// private List<Integer> selectIndexRoles = new ArrayList<>();
public ChartYdate(Context context) {
super(context);
}
public ChartYdate(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ChartYdate(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
LogUtil2.log("yData--------------->onDraw画布"+ypCount);
initChartYdateProp();
initCoordinateSystem(canvas);
//开始动画
if (isAnim){
initAnims();
post(animator);
isAnim = false;
}
}
/*
* 初始化统计图属性
*/
private void initChartYdateProp() {
//x轴宽度
xWidth = getWidth() - getPaddingLeft() - getPaddingRight() - yTextSurplus;
//y轴宽度
yHeight = getHeight() - getPaddingTop() - getPaddingBottom() - xTextSurplus;
//x轴每个刻度的间距
xSpacing = (xWidth-xSurplus-xWidth%xpCount)/xpCount;
//y轴每个刻度的间距
ySpacing = (yHeight-ySurplus-yHeight%ypCount)/ypCount;
//坐标系原点x
oX = getPaddingLeft()+yTextSurplus;
//坐标系原点y 减70为了画出当月图片
oY = getPaddingTop()+yHeight+xTextSurplus/2-70;
//x轴各刻度点位置
xCoordinates = new int[xpCount];
//y轴各刻度点位置
yCoordinates = new int[ypCount];
//记录x轴刻度点位置 修改柱形图离坐标原点的距离
for (int i=0; i<xpCount; i++){
xCoordinates[i] = (i+1) * xSpacing- 30;
}
LogUtil2.log("yData--------------->ypCount记录y轴刻度点位置"+ypCount);
//记录y轴刻度点位置
for (int j=0; j<ypCount; j++){
yCoordinates[j] = (j+1) * ySpacing;
LogUtil2.log("yData--------------->henghe"+yCoordinates[j]);
}
LogUtil2.log("yData--------------->yCoordinates记录y轴刻度点位置"+yCoordinates.length);
}
/*
* 初始化坐标系
*/
private void initCoordinateSystem(Canvas canvas){
Paint mainPaint = new Paint();
mainPaint.setColor(coordinates_color);
mainPaint.setAntiAlias(true);
//draw x 坐标
// canvas.drawLine(oX,oY, oX,oY-yHeight,mainPaint);
//draw y 坐标
// canvas.drawLine(oX,oY,oX+xWidth+40,oY,mainPaint);
//刻度值画笔
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(getResources().getColor(R.color.transparent));
mTableValuePaint = new Paint();
mTableValuePaint.setStrokeWidth(DensityUtil.dip2px(getContext(), 0.04f));
mTableValuePaint.setStyle(Paint.Style.FILL);
mTableValuePaint.setColor(ContextCompat.getColor(getContext(), R.color.text_666666));
mTableValuePaint.setAntiAlias(true);
mTableValuePaint.setTextSize(DensityUtil.dip2px(getContext(), 13));
//draw x 刻度
for (int i=0; i<xCoordinates.length; i++){
//更改文字大小
// textPaint.setTextSize(x_text_size);
textPaint.setTextSize(getResources().getDimension(R.dimen.font_9));
//更改文字颜色
textPaint.setColor(x_text_color);
//x轴刻度线
// canvas.drawLine(oX+xCoordinates[i],oY,oX+xCoordinates[i],oY-5,mainPaint);
//获取x轴文字宽高
if (xData!=null&&xData.length>0){
int[] textSize = getTextSize(xData[i],textPaint);
//计算x轴文字x,y坐标偏移量
int textX = textSize[0]/2;
int textY = xTextSurplus/2 - textSize[1]/2;
//画x轴文字
canvas.drawText(xData[i],oX+xCoordinates[i]-textX,oY+textY,textPaint);
String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
Integer year = Integer.parseInt(strNow[0]);
Integer month = Integer.parseInt(strNow[1]);
//画当前月图片 + DensityUtil.dip2px(mContext, 6)
if (month == Integer.parseInt(xData[i])) {
Bitmap arrow = BitmapFactory.decodeResource(getResources(), R.mipmap.current_month);
RectF rectF = new RectF((float) (oX+xCoordinates[i]-textX - DensityUtil.dip2px(getContext(), 10)),
(float) (oY+textY+60 - DensityUtil.dip2px(getContext(), 15)),
(float) (oX+xCoordinates[i]-textX + DensityUtil.dip2px(getContext(), 20)),
(float) (oY+textY+70 - DensityUtil.dip2px(getContext(), 3)));
canvas.drawBitmap(arrow, null, rectF, textPaint);
}
}
}
if(yMax == 0f){
yMax = getYMax();
}
if(getYMax()==0){
yMax=1.0f;
}
//draw y 刻度
for (int j=0; j<ypCount; j++){
//更改文字大小
textPaint.setTextSize(y_text_size);
//y轴刻度线
// canvas.drawLine(oX,oY-yCoordinates[j],oX+5,oY-yCoordinates[j],mainPaint);
//y轴刻度值
int iYMax = (int)yMax;
String datay;
if (yMax - iYMax == 0){
datay = (int)(yMax/ypCount*(j+1))+"";
}else {
datay = new DecimalFormat("0.000").format(yMax/ypCount*(j+1));
}
//平均分成4份
// Double mMaxDiv = DoubleUtils.getLargerInterger(yMax, 7);
// datay= String.valueOf((new BigDecimal((j + 1) * mMaxDiv).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
int att=(int) Math.floor(yMax);
String mBigst=String.valueOf(att);
// String mBigst=String.valueOf(yMax).substring(0, String.valueOf(yMax).indexOf("."));
int maxLength=mBigst.length();
int baseMax= att+1;
if (maxLength>=2){
baseMax= Integer.valueOf(mBigst.substring(0, 2))+1;
}
boolean isBreak=false;
int margCount=0;
String ii="";//画y轴最大值
String aa="";//间隔
for (int i=baseMax;i<baseMax+100;i++){
for (int a=100;a>0;a--){
if (i%a==0&&i/a<=6&&i/a>=4){
margCount=i/a;
ii= String.valueOf(i);
aa=String .valueOf(a);
isBreak=true;
break;
}
}
if (isBreak)
break;
}
for (int y=0;y<maxLength-2;y++){
aa=aa+"0";
ii=ii+"0";
}
// double mm=formatTosepara2(Double.valueOf(aa));
// int mm+=Integer.parseInt(aa)*j;
//String.valueOf(Integer.parseInt(aa)*(j+1))
datay= formatTosepara2(Double.valueOf(Integer.parseInt(aa)*(j+1)));
//
LogUtil2.log("ydate---+++"+datay+"---"+ii);
//获取文字宽高
int[] textSize = getTextSize(datay,textPaint);
//计算画文字的坐标偏移量
int textX = yTextSurplus/2 + textSize[0]/2;
int textY = textSize[1]/2;
//画y轴文字
textPaint.setColor(y_text_color);
if (j==0){
canvas.drawText("0",oX-textX,oY,textPaint);
}
canvas.drawText(datay,oX-textX,oY-yCoordinates[j]+textY,textPaint);
}
LogUtil2.log("ydate---+++"+yData.toString());
}
public String formatTosepara2(double data) {
int length = String.valueOf(data).split("\\.")[0].length();
if (length < 4) {
return String.format("%.2f", data);
}
DecimalFormat df = new DecimalFormat("##,###");
return df.format(data);
}
/*
* 准备动画
*/
private void initAnims() {
anims = new Anim[xpCount];
// switch (animType){
// case Anim.ANIM_TRANSLATE:
// for (int i=0;i<xpCount;i++){
// float dataX = oX+xCoordinates[i];
// float dataY = oY-yData[i]/yMax*yCoordinates[yCoordinates.length-1];
// Anim anim = new Anim(dataX,dataY,dataX,oY);
// anim.setAnimation(new TranslateAnim());
// anim.setVelocity(interval*2);
// anims[i] = anim;
// }
// break;
// case Anim.ANIM_ALPHA:
// for (int i=0;i<xpCount;i++){
// float dataX = oX+xCoordinates[i];
// float dataY = oY-yData[i]/yMax*yCoordinates[yCoordinates.length-1];
// Anim anim = new Anim(dataX,dataY,dataX,dataY);
// anim.setAnimation(new AlphaAnim());
// anim.setAlpha(0);
// anim.setVelocity(interval * 3/2);
// anims[i] = anim;
// }
// break;
// default:
// for (int i=0;i<xpCount;i++){
// float dataX = oX+xCoordinates[i];
// float dataY = oY-yData[i]/yMax*yCoordinates[yCoordinates.length-1];
// Anim anim = new Anim(dataX,dataY,dataX,dataY);
// anim.setAnimation(new TranslateAnim());
// anim.setVelocity(interval);
// anims[i] = anim;
// }
for (int i=0;i<xpCount;i++){
float dataX = oX+xCoordinates[i];
LogUtil2.log("yData----------dataX"+oX+xCoordinates[i]);
LogUtil2.log("yData----------yData"+yData.length);
LogUtil2.log("yData----------xpCount"+xpCount);
LogUtil2.log("yData----------yCoordinates"+yCoordinates.length);
//平均分成4份
Double mMaxDi = DoubleUtils.getLargerInterger(yMax, 7);
//设置Y轴分值
float total=0;
// float total= (float) new BigDecimal((7) * mMaxDi).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
LogUtil2.log("最大值--"+yMax);
int att=(int) Math.floor(yMax);
String mBigst=String.valueOf(att);
// String mBigst=String.valueOf((int) Math.floor(yMax));
LogUtil2.log("最大值--"+yMax+"---"+mBigst);
// String mBigst=String.valueOf(yMax).substring(0, String.valueOf(yMax).indexOf("."));
int maxLength=mBigst.length();
int baseMax= att+1;
if (maxLength>=2){
baseMax= Integer.valueOf(mBigst.substring(0, 2))+1;
}
boolean isBreak=false;
String aa="";//间隔值
String ii="";//y轴最大
int margCount=0;//分多少份,动态设置
for (int j=baseMax;j<baseMax+100;j++){
for (int a=100;a>0;a--){
if (j%a==0&&j/a<=6&&j/a>=4){
margCount=j/a;
aa=String.valueOf(a);
ii=String.valueOf(j);
isBreak=true;
break;
}
}
if (isBreak)
break;
}
for (int y=0;y<maxLength-2;y++){
aa=aa+"0";
ii=ii+"0";
// total= Float.parseFloat(String.valueOf(baseMax)+"0");
}
LogUtil2.log("total"+total);
total= Float.parseFloat(ii);
LogUtil2.log("aa--"+aa+"--total"+total);
float dataY = oY-yData[i]/total*yCoordinates[yCoordinates.length-1];
LogUtil2.log("yData----------dataY"+dataY);
Anim anim = new Anim(dataX,dataY,dataX,dataY);
anim.setAnimation(new TranslateAnim());
anim.setVelocity(interval);
anims[i] = anim;
LogUtil2.log("yData----------anims"+anims);
}
// break;
// }
}
/*
* 获取y轴最大值
*/
protected float getYMax(){
if (yData == null || yData.length == 0){
yData = new float[ypCount];
}
float max =0;
for (int i=0; i<yData.length; i++){
if (max < yData[i]){
max = yData[i];
}
}
return max;
}
/*
* 获取文字宽高
*/
protected int[] getTextSize(String str,Paint paint){
//计算文字所在矩形,可以得到宽高
Rect rect = new Rect();
paint.getTextBounds(str, 0, str.length(), rect);
int w = rect.width();
int h = rect.height();
return new int[]{w,h};
}
/*
* 设置统计图属性
*/
public void setChartYdateData(ChartData chartData) {
if (chartData == null){
throw new NullPointerException("折线图数据不能为空!");
}
this.xData = chartData.getXdata();
this.yData = chartData.getYdata();
this.xpCount = getFinalValue(this.xpCount,chartData.getXpCount());
this.ypCount = getFinalValue(this.ypCount,chartData.getYpCount());
this.coordinates_color = getFinalValue(this.coordinates_color,chartData.getCoordinatesColor());
this.x_text_size = getFinalValue(this.x_text_size,chartData.getxTextSize());
this.y_text_size = getFinalValue(this.y_text_size,chartData.getyTextSize());
this.x_text_color = getFinalValue(this.x_text_color,chartData.getxTextColor());
this.y_text_color = getFinalValue(this.y_text_color,chartData.getyTextColor());
this.interval = getFinalValue((int) this.interval,chartData.getInterval());
// this.animType = chartData.getAnimType() != -2 ? chartData.getAnimType()
// : this.animType;
this.yMax = chartData.getyMax() != 0f ? chartData.getyMax() : this.yMax;
}
/*
* 设置正确属性值
*/
protected int getFinalValue(int old,int news){
old = news != 0 ? news : old;
return old;
}
/*
* 执行动画runnable
*/
private Runnable animator = new Runnable() {
@Override
public void run() {
LogUtil2.log("yData----------anims循环"+anims);
LogUtil2.log("yData----------anims长多"+anims.length);
for(Anim a : anims){
LogUtil2.log("yData----------anims循环2"+a.isOver());
if(!a.isOver()){
a.refresh();
postDelayed(this, interval);
invalidate();
return;
}
}
}
};
/*
* 更新数据并重绘
*/
public void update(ChartData chartData){
yMax = 0;
setChartYdateData(chartData);
isAnim = true;
invalidate();
}
/* @Override
public boolean onTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
int left = 0;
int top = 0;
int right = xWidth/ 12;
int bottom = yHeight;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 0; i < 12; i++) {
Rect rect = new Rect(left, top, right, bottom);
left += xWidth / 12;
right += xWidth / 12;
if (rect.contains(x, y)) {
if (listener != null) {
listener.getNumber(i, x, y);
// isSelect=true;
// number = i;
selectIndex = i;
selectIndexRoles.clear();
selectIndexRoles.add(selectIndex);
invalidate();
}
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
public void setListener(getNumberListener listener) {
this.listener = listener;
}
public interface getNumberListener {
void getNumber(int number, int x, int y);
}*/
}
3.布局 activity_family_status嵌套在Scrollowview中
<android.support.v4.widget.NestedScrollView
android:id="@+id/scrollowview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:layout_marginBottom="@dimen/lay_10"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<com.broker.liming.widget.HistogramRound
android:id="@+id/histogramchart"
android:layout_width="@dimen/lay_320"
android:layout_height="220dp"
android:layout_marginLeft="@dimen/lay_12"
chart:hCoordinatesColor="@color/text_999999"
chart:hxTextColor="@color/color_6a6a6a"
chart:hyTextColor="@color/color_1FA6FB"
/>
<LinearLayout/>
<android.support.v4.widget.NestedScrollView/>
4.运用FamilyStatusActivity
package com.broker.liming.activity;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.RequiresApi;
import android.support.v4.widget.NestedScrollView;
import android.support.v7.widget.LinearLayoutManager;
import com.broker.liming.utils.ArithUtil;
import com.broker.liming.utils.BarUtils;
import com.broker.liming.utils.GsonUtils;
import com.broker.liming.utils.LogUtil2;
import com.broker.liming.utils.UIHelper;
import com.broker.liming.widget.HistogramData;
import com.broker.liming.widget.HistogramRound;
import com.broker.liming.widget.TitleBar;
import org.json.JSONException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import butterknife.BindView;
import static com.sobot.chat.utils.ScreenUtils.dip2px;
import static com.sobot.chat.utils.ScreenUtils.px2dip;
/**
* @Descpription:家庭现状
* @Date: 2019/7/17.
* @author:chenhuirong
*/
public class FamilyStatusActivity extends BaseActivity{
@BindView(R.id.histogramchart)
HistogramRound histogramChart;
@BindView(R.id.scrollowview)
NestedScrollView scrollowview;
private FamilyStatusAdapter adapter;
private FamilyStatusRateAdapter rateAdapter;
private HistogramData histogramData;
//柱状图
// @BindView(R.id.my_single_chart_view)
// SingleView mMySingleChartView;
@BindView(R.id.rl_single)
RelativeLayout rlSingle;
private List<Float> singlelist;
private LinearLayout llSingle;
private double mMax = 44;
private List<FamilyPremiumArrayBean> listData = new ArrayList<>();
private String monthBack;
float[] ydata = new float[12];
private String[] xdata= new String[12] ;
private String[] xdataShow= new String[12] ;//仅为显示
private boolean isScrollow=true;
private boolean isFresh=false;
int margCount=0;//共分多少份
private LinearLayout line;
private String name;
public static void actionStart(Context context, String familyUuid,String names) {
Intent intent = new Intent(context, FamilyStatusActivity.class);
intent.putExtra("familyUuid", familyUuid);
intent.putExtra("name",names);
context.startActivity(intent);
}
@Override
protected void initTitleBar() {
TitleBar titleBar = (TitleBar) findViewById(R.id.title_bar);
assert titleBar != null;
/*titleBar.setLeftBackground(R.mipmap.back);*/
titleBar.setLeftBackground(R.mipmap.order_back);
titleBar.setTitle(name+"的家庭数据分析");
titleBar.setTitleColor(R.color.text_000000);
titleBar.setTitleBarBg(getResources().getColor(R.color.white));
titleBar.setLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
protected int getContentView() {
return R.layout.activity_family_status;
}
@Override
protected boolean initBundle(Bundle bundle) {
}
@Override
public void initData() {
super.initData();
}
@Override
protected void onResume() {
super.onResume();
getPieDate(familyUuid);
}
public void getHomeData() {
try {
UserBean query = UserBeanDao.query();
requestServerPostForm(false, 100, HttpParams.getFamilyStatus(query, familyUuid));
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void initView() {
xdata=new String[]{"1","2","3","4","5","6","7","8","9","10","11","12"};
xdataShow=new String[]{"01","02","03","04","05","06","07","08","09","10","11","12"};
initSingle();
scrollowview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
LogUtil2.log("onDraw--getX---isScrollow" +isScrollow);
float x=0;
float y=0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
LogUtil2.log("onDraw--getX---down" + event.getX() + "---" + y);
break;
case MotionEvent.ACTION_MOVE:
LogUtil2.log("onDraw--getX---move:" + event.getX() + "---");
// isFresh=true;
//在此刷新柱状图,防止多次刷新,多次重绘
if (isScrollow){
rlSingle.removeView(llSingle);
rlSingle.removeView(line);
histogramChart.setPublicRefresh();
// histogramChart.isScrollow(isFresh);
isScrollow=false;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
//
//允许ScrollView截断点击事件,ScrollView可滑动
LogUtil2.log("onDraw--getX---up" + event.getX() + "mLastWownY:" + event.getY()+"x差值:"+Math.abs(ArithUtil.sub(event.getX(), x))+"--y差值:"+ Math.abs(ArithUtil.sub(event.getY(), y)) );
//抬起坐标减去放下坐标绝对值小于20代表点击,否则代表滑动
/* if (Math.abs(ArithUtil.sub(event.getX(), x)) <= 20 && Math.abs(ArithUtil.sub(event.getY(), y)) <= 20) {
// isScrollow=false;
isCheck=true;
}else {
// isScrollow=true;
isCheck=false;
histogramChart.isScrollow(false);
rlSingle.removeView(llSingle);
rlSingle.removeView(line);
if (isScrollow){
histogramChart.setPublicRefresh();
isScrollow=false;
}
}*/
break;
}
return false;
}
});
changeStatusBarTextColor(true);
BarUtils.setColorNoTranslucent(this, getResources().getColor(R.color.white));
}
/**
* 弹出弹框
*/
private void initSingle(){
rlSingle = (RelativeLayout) findViewById(R.id.rl_single);
singlelist = new ArrayList<>();
rlSingle.removeView(llSingle);
rlSingle.removeView(line);
histogramChart.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
LogUtil2.log("onDraw--getX---弹框的长按事件:" + isScrollow);
return false;
}
});
histogramChart.setListener(new HistogramRound.getNumberListener() {
@Override
public void getNumber(int index, int height, int left,int selectorHeight,int ox) {
// rlSingle.removeAllViews();
LogUtil2.log("onDraw--getX---弹框:" + isScrollow);
isScrollow=true;
// if(!isFresh){
rlSingle.removeView(llSingle);
rlSingle.removeView(line);
line= (LinearLayout) LayoutInflater.from(FamilyStatusActivity.this).inflate(R.layout.layout_dash_line, null);
// TextView view=new TextView(mContext);
// view.setBackground(mContext.getResources().getDrawable(R.drawable.shape_dash_line));
RelativeLayout.LayoutParams viewParam=new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);viewParam. topMargin=height-selectorHeight;
viewParam.topMargin=selectorHeight-5;
viewParam.leftMargin=dip2px(mContext,40);
viewParam.rightMargin=dip2px(mContext,30);
line.setLayoutParams(viewParam);
rlSingle.addView(line);
llSingle = (LinearLayout) LayoutInflater.from(FamilyStatusActivity.this).inflate(R.layout.layout_pro_expense, null);
LinearLayout ll_back=(LinearLayout)llSingle.findViewById(R.id.ll_back);
TextView tvMoney = (TextView) llSingle.findViewById(R.id.tv_month);
TextView tv_money=(TextView) llSingle.findViewById(R.id.tv_money);
if (singlelist!=null&&singlelist.size()>0){
tv_money.setText(formatTosepara2(singlelist.get(index))+"");
}else {
tv_money.setText("0");
}
String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
String year = strNow[0];
tvMoney.setText(year+"-"+xdataShow[index]);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
LogUtil2.log("setSelect--callback--"+height+"--left---"+left+"---"+selectorHeight+"弹框高--"+dip2px(mContext,60)+"--差值--"+(height-(height-selectorHeight/*+px2dip(mContext,70)*/)-dip2px(mContext,60)));
LogUtil2.log("----宽-----+++"+params.width);
LogUtil2.log("setSelect--转换"+px2dip(mContext,height)+"--left---"+px2dip(mContext,left)+"---"+dip2px(mContext,selectorHeight));
int topmargin=0;
int leftmargin=0;
LogUtil2.log("setSelect--差距"+px2dip(mContext,height-selectorHeight));
if (index+1>6){
if (height-(height-selectorHeight)-dip2px(mContext,60)-dip2px(mContext,5)>0){
ll_back.setBackground(mContext.getResources().getDrawable(R.mipmap.right_bottom));
topmargin=height-(height-selectorHeight)-dip2px(mContext,60)-dip2px(mContext,5)/*+dip2px(mContext,70)*/;
}else {
topmargin= height-(height-selectorHeight)+dip2px(mContext,5)/*+dip2px(mContext,70)*/;
ll_back.setBackground(mContext.getResources().getDrawable(R.mipmap.right_top));
}
//
leftmargin=left-dip2px(mContext,150)+dip2px(mContext,40);
}else {
if (height-(height-selectorHeight)-dip2px(mContext,60)-dip2px(mContext,5)>0){
ll_back.setBackground(mContext.getResources().getDrawable(R.mipmap.left_bottom));
topmargin=height-(height-selectorHeight)-dip2px(mContext,60)-dip2px(mContext,5);
}else {
ll_back.setBackground(mContext.getResources().getDrawable(R.mipmap.left_top));
topmargin=height-(height-selectorHeight)+dip2px(mContext,5);
}
leftmargin=left;
}
params.leftMargin = leftmargin;
//相当于总布局的上方,需要减去家庭保费和保费距离
params.topMargin=topmargin/* selectorHeight+px2dip(mContext,64)*/;
// LogUtil2.log("setSelect--callback--"+histogramChart.getHeight()+"---"+selectorHeight+"---left"+ params.topMargin);
// if (x - 100 < 0) {
// params.leftMargin = 0;
// } else if (x - 100 > relativeLayout.getWidth() - llSingle.getMeasuredWidth()) {
// params.leftMargin = relativeLayout.getWidth() - llSingle.getMeasuredWidth();
// }
llSingle.setLayoutParams(params);
rlSingle.addView(llSingle);
// }
}
});
}
private void changeStatusBarTextColor(boolean isBlack) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (isBlack) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//设置状态栏黑色字体
}else {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);//恢复状态栏白色字体
}
}
}
private void setDate(FamilyYearCheakBean yearCheakBean) {
if (yearCheakBean != null) {
if (yearCheakBean.familyPremiumTotal != null && !yearCheakBean.familyPremiumTotal.equals("")) {
tv_total_money.setText("合计年缴"+formatTosepara(Double.valueOf(String.valueOf(yearCheakBean.familyPremiumTotal))) + "元");
}else {
tv_total_money.setText("合计年缴0.00元");
}
String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
Integer year = Integer.parseInt(strNow[0]);
Integer month = Integer.parseInt(strNow[1]);
listData = yearCheakBean.familyPremiumArray;
List<Double> list = new ArrayList<>();
ArrayList<DotVo> temp = new ArrayList();
for (int i = 0; i < listData.size(); i++) {
FamilyPremiumArrayBean bean = listData.get(i);
String yearback = bean.MONTH.substring(0, bean.MONTH.indexOf("-"));
monthBack = bean.MONTH.substring(bean.MONTH.lastIndexOf("-") + 1);
// mXdots[i] = yearback + "年\n" + monthBack + "月";
list.add(Double.valueOf(bean.premium));
double premium = 0;
if (bean.premium != null && !bean.premium.equals("")) {
premium = Double.valueOf(bean.premium);
list.add(Double.valueOf(bean.premium));
singlelist.add(Float.valueOf(bean.premium));
ydata[i]=Float.valueOf(bean.premium);
}
DotVo tempDotVo = new DotVo(monthBack, premium);
temp.add(tempDotVo);
}
Double[] toBeStored = list.toArray(new Double[list.size()]);
mMax = checkMax(toBeStored);
}
//向下取整
int att=(int) Math.floor(mMax);
String mBigst=String.valueOf(att);
int maxLength=mBigst.length();
int baseMax= att+1;
if (maxLength>=2){
baseMax= Integer.valueOf(mBigst.substring(0, 2))+1;
}
boolean isBreak=false;
for (int i=baseMax;i<baseMax+100;i++){
for (int a=100;a>0;a--){
if (i%a==0&&i/a<=6&&i/a>=4){
margCount=i/a;
isBreak=true;
break;
}
}
if (isBreak)
break;
}
for (int i=0;i<maxLength-2;i++){
}
LogUtil2.log("ydata---设置数据"+ydata.toString()+"--最大分数--"+margCount);
histogramData = HistogramData.builder()
.setXdata(xdata)
.setYdata(ydata)
.setYpCount(margCount)
// .setAnimType(Anim.ANIM_ALPHA)
.build();
histogramChart.setChartYdateData(histogramData);
histogramChart.update(histogramData);
}
public double checkMax(Double[] args) {
double max = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] > max) {
max = args[i];
}
}
return max;
}
@Override
protected void onSuccess(String response, int id) {
super.onSuccess(response, id);
switch (id){
case 200:
yearCheakBean= GsonUtils.toObject(response,FamilyYearCheakBean.class);
setDate(yearCheakBean);
break;
}
}
/**
* 将float类型的数据转换成以4位逗号隔开的字符串,并且保留两位有效数字
*/
public String formatTosepara(double data) {
int length = String.valueOf(data).split("\\.")[0].length();
if (length < 4) {
return String.format("%.2f", data);
}
DecimalFormat df = new DecimalFormat("#,####.00");
return df.format(data);
}
public String formatTosepara2(double data) {
int length = String.valueOf(data).split("\\.")[0].length();
if (length < 4) {
return String.format("%.2f", data);
}
DecimalFormat df = new DecimalFormat("##,###");
return df.format(data);
}
}
5.HistogramData
package com.broker.liming.widget;
import com.broker.liming.bean.ChartData;
/**
* @author chenhuirong
* @Date 2018/12/10
* @Description 柱状图s
*/
public class HistogramData extends ChartData {
private int[] rectColor;
private int rectTextColor;
private int rectTextSize;
private HistogramData(Builder builder) {
setXdata(builder.xdata);
setYdata(builder.ydata);
setXpCount(builder.xpCount);
setYpCount(builder.ypCount);
setCoordinatesColor(builder.coordinatesColor);
setxTextSize(builder.xTextSize);
setyTextSize(builder.yTextSize);
setxTextColor(builder.xTextColor);
setyTextColor(builder.yTextColor);
setyMax(builder.yMax);
setInterval(builder.interval);
setAnimType(builder.animType);
setRectColor(builder.rectColor);
setRectTextColor(builder.rectTextColor);
setRectTextSize(builder.rectTextSize);
}
public static Builder builder() {
return new Builder();
}
public int[] getRectColor() {
return rectColor;
}
public void setRectColor(int[] rectColor) {
this.rectColor = rectColor;
}
public int getRectTextColor() {
return rectTextColor;
}
public void setRectTextColor(int rectTextColor) {
this.rectTextColor = rectTextColor;
}
public int getRectTextSize() {
return rectTextSize;
}
public void setRectTextSize(int rectTextSize) {
this.rectTextSize = rectTextSize;
}
public static final class Builder{
private int rectTextSize;
private int rectTextColor;
private int[] rectColor;
private int animType;
private int interval;
private int yMax;
private int yTextColor;
private int xTextColor;
private int yTextSize;
private int xTextSize;
private int coordinatesColor;
private int ypCount;
private int xpCount;
private float[] ydata;
private String[] xdata;
private Builder(){}
public Builder setRectTextSize(int val) {
rectTextSize = val;
return this;
}
public Builder setRectTextColor(int val) {
rectTextColor = val;
return this;
}
public Builder setRectColor(int[] val) {
rectColor = val;
return this;
}
public Builder setAnimType(int val) {
animType = val;
return this;
}
public Builder setInterval(int val) {
interval = val;
return this;
}
public Builder setYMax(int val) {
yMax = val;
return this;
}
public Builder setYTextColor(int val) {
yTextColor = val;
return this;
}
public Builder setXTextColor(int val) {
xTextColor = val;
return this;
}
public Builder setYTextSize(int val) {
yTextSize = val;
return this;
}
public Builder setXTextSize(int val) {
xTextSize = val;
return this;
}
public Builder setCoordinatesColor(int val) {
coordinatesColor = val;
return this;
}
public Builder setYpCount(int val) {
ypCount = val;
return this;
}
public Builder setXpCount(int val) {
xpCount = val;
return this;
}
public Builder setYdata(float[] val) {
ydata = val;
return this;
}
public Builder setXdata(String[] val) {
xdata = val;
return this;
}
public HistogramData build() {
return new HistogramData(this);
}
}
}
6.ChartData
package com.broker.liming.bean;
/**
* 统计图父类数据类
* Created by zqx on 16/6/27.
*/
public class ChartData {
protected String[] xdata;
protected float[] ydata;
protected int xpCount;
protected int ypCount;
protected int coordinatesColor;
protected int xTextSize;
protected int yTextSize;
protected int xTextColor;
protected int yTextColor;
protected int yMax;
protected int interval;
protected int animType = -2;
protected ChartData(){}
public String[] getXdata() {
return xdata;
}
public void setXdata(String[] xdata) {
this.xdata = xdata;
}
public float[] getYdata() {
return ydata;
}
public void setYdata(float[] ydata) {
this.ydata = ydata;
}
public int getXpCount() {
return xpCount;
}
public void setXpCount(int xpCount) {
this.xpCount = xpCount;
}
public int getYpCount() {
return ypCount;
}
public void setYpCount(int ypCount) {
this.ypCount = ypCount;
}
public int getCoordinatesColor() {
return coordinatesColor;
}
public void setCoordinatesColor(int coordinatesColor) {
this.coordinatesColor = coordinatesColor;
}
public int getxTextSize() {
return xTextSize;
}
public void setxTextSize(int xTextSize) {
this.xTextSize = xTextSize;
}
public int getyTextSize() {
return yTextSize;
}
public void setyTextSize(int yTextSize) {
this.yTextSize = yTextSize;
}
public int getxTextColor() {
return xTextColor;
}
public void setxTextColor(int xTextColor) {
this.xTextColor = xTextColor;
}
public int getyTextColor() {
return yTextColor;
}
public void setyTextColor(int yTextColor) {
this.yTextColor = yTextColor;
}
public int getyMax() {
return yMax;
}
public void setyMax(int yMax) {
this.yMax = yMax;
}
public int getInterval() {
return interval;
}
public void setInterval(int interval) {
this.interval = interval;
}
public int getAnimType() {
return animType;
}
public void setAnimType(int animType) {
this.animType = animType;
}
}
注:参考demo时间太久我忘记了,网上可找到