自定义 view 在 Android 开发中会经常用到,本项目是一个很好的学习例子,如果有空可以看一下哟!
来看下效果图:
自定义 view 代码:
/**
* Created by kn on 2016/11/1.
* <p/>
* 折线图
*/
public class LineChart extends View {
private int mWidth, mHeight;//View 的宽和高
private float mFontSize = 12;//字体的大小
private float mStrokeWidth = 1.5f;//线条的宽度
private float mPointRadius = 2;//点的半径
private int mDateTextColor = Color.parseColor("#cfcfcf");//日期字体颜色
private int mDarkColor = Color.parseColor("#5b7fdf");//点、线的颜色(深色)
private int mLightColor = Color.parseColor("#d5d8f7");//点、线的颜色(浅色)
private int mShapeColor = Color.parseColor("#f3f6fd");//阴影的颜色
private String[] mXItems;//X轴的文字
private int[] mPoints;//点的数组,-1表示该日还没到
private int mLength = 7;//最大比例
private Paint mDatePaint = new Paint();//日期画笔
private Paint mPointPaint = new Paint();//点画笔
private Paint mLinePaint = new Paint();//线条画笔
private Paint mShapePaint = new Paint();//阴影部分画笔
private int max = 7;
private Context mContext;
public LineChart(Context context) {
this(context, null);
}
public LineChart(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LineChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
TypedArray typedArray = mContext.getTheme().obtainStyledAttributes(attrs, R.styleable.LineChart, 0, 0);
try {
mDateTextColor = typedArray.getColor(R.styleable.LineChart_DateTextColor, mDateTextColor);
mDarkColor = typedArray.getColor(R.styleable.LineChart_DarkColor, mDarkColor);
mLightColor = typedArray.getColor(R.styleable.LineChart_LightColor, mLightColor);
mShapeColor = typedArray.getColor(R.styleable.LineChart_ShapeColor, mShapeColor);
mFontSize = typedArray.getDimensionPixelSize(R.styleable.LineChart_FontSize,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mFontSize, mContext.getResources().getDisplayMetrics()));
mStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.LineChart_StrokeWidth,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mStrokeWidth, mContext.getResources().getDisplayMetrics()));
mPointRadius = typedArray.getDimensionPixelSize(R.styleable.LineChart_PointRadius,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPointRadius, mContext.getResources().getDisplayMetrics()));
} finally {
typedArray.recycle();
}
initPaint();
}
private void initPaint() {
//日期画笔
mDatePaint.setTextSize(mFontSize);
mDatePaint.setColor(mDateTextColor);
//点画笔
mPointPaint.setTextSize(mFontSize);
mPointPaint.setColor(mDarkColor);
//先画笔
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeWidth(mStrokeWidth);//设置线条宽度
mLinePaint.setStyle(Paint.Style.FILL);
mLinePaint.setColor(mDarkColor);
//阴影部分画笔
mShapePaint.setAntiAlias(true);
mShapePaint.setStyle(Paint.Style.FILL);
mShapePaint.setColor(mShapeColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
mWidth = widthSize;
mHeight = heightSize;
// if (widthMode == MeasureSpec.EXACTLY) {
// mWidth = widthSize;
// } else if (widthMode == MeasureSpec.AT_MOST) {
// mWidth = widthSize;
// }
//
// if (heightMode == MeasureSpec.EXACTLY) {
// mHeight = heightSize;
// } else if (heightMode == MeasureSpec.AT_MOST) {
// mHeight = mWidth / 7 * 3;
// }
if (heightMode == MeasureSpec.AT_MOST) {
mHeight = mWidth / 7 * 3;
}
setMeasuredDimension(mWidth, mHeight);
}
private float mAnimatedValue = 0f;
protected void OnAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatedValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
public ValueAnimator valueAnimator;
private ValueAnimator startViewAnim(float startF, final float endF, long time) {
valueAnimator = ValueAnimator.ofFloat(startF, endF);
valueAnimator.setDuration(time);
valueAnimator.setInterpolator(new LinearInterpolator());
// valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
// valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
OnAnimationUpdate(valueAnimator);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
});
if (!valueAnimator.isRunning()) {
valueAnimator.start();
}
return valueAnimator;
}
@Override
protected void onDraw(Canvas canvas) {
if (mXItems == null) {
mXItems = new String[]{"日", "一", "二", "三", "四", "五", "六"};
mPoints = new int[]{0, -1, -1, -1, -1, -1, -1};
mLength = mXItems.length;
}
//最大比例
for (int i = 0; i < mLength; i++) {
if (mPoints[i] > max) {
max = mPoints[i];
}
}
//原点坐标
int xOrigin = (int) (0.5 * (mWidth / mLength) - mFontSize / 2);
int yOrigin = (int) (max * ((mHeight - mLength * mFontSize) / max) + 4 * mFontSize);
int[] xPoints = new int[mLength];//x轴的刻度集合
int[] yPoints = new int[mLength];//y轴的刻度集合
canvas.save();
for (int i = 0; i < mLength; i++) {
//获取点的坐标
xPoints[i] = (int) ((i + 0.5) * (mWidth / mLength));
//todo
yPoints[i] = (int) ((max - (mPoints[i] == -1 ? 0 : mPoints[i]) * mAnimatedValue) * ((mHeight - mLength * mFontSize) / max) + 4 * mFontSize);
if (i > 0) {
//画一个实心梯形,阴影部分
Path path = new Path();
path.moveTo(xPoints[i - 1], yOrigin + mPointRadius / 2);
path.lineTo(xPoints[i - 1], yPoints[i - 1]);
path.lineTo(xPoints[i], yPoints[i]);
path.lineTo(xPoints[i], yOrigin + mPointRadius / 2);
path.close();
canvas.drawPath(path, mShapePaint);
}
//画出日期
canvas.drawText(mXItems[i], (int) ((i + 0.5) * mWidth / mLength) - mFontSize / 2, mHeight - mFontSize, mDatePaint);
}
for (int i = 0; i < mLength; i++) {
if (mPoints[i] == -1) {
mLinePaint.setColor(mLightColor);
mPointPaint.setColor(mLightColor);
} else {
mLinePaint.setColor(mDarkColor);
mPointPaint.setColor(mDarkColor);
}
if (i > 0) {
//画连线
canvas.drawLine(xPoints[i - 1], yPoints[i - 1], xPoints[i], yPoints[i], mLinePaint);
}
//画点的数值
//todo
canvas.drawText(String.valueOf(mPoints[i]).equals("-1") ? " " : new BigDecimal(String.valueOf(mPoints[i] * mAnimatedValue)).setScale(0, BigDecimal.ROUND_HALF_UP) + ""
// String.valueOf(mPoints[i])
, xPoints[i] - mFontSize / 4, yPoints[i] - mFontSize, mPointPaint);
}
for (int i = 0; i < mLength; i++) {
if (mPoints[i] == -1) {
mLinePaint.setColor(mLightColor);
mPointPaint.setColor(mLightColor);
} else {
mLinePaint.setColor(mDarkColor);
mPointPaint.setColor(mDarkColor);
}
//画点
canvas.drawCircle(xPoints[i], yPoints[i], mPointRadius, mPointPaint);
}
canvas.restore();
}
public void setData(List<LineChartData> dataList) {
mLength = dataList.size();
if (mLength > 0) {
mXItems = new String[mLength];
mPoints = new int[mLength];
for (int i = 0; i < mLength; i++) {
mPoints[i] = dataList.get(i).getPoint();
mXItems[i] = dataList.get(i).getItem();
}
}
startViewAnim(0f, 1f, 1000);
invalidate();
}
}