一、前言:
最近一个项目中涉及到了自定义环形图和柱状图的功能,闲暇之余,记录一下实现过程,文末会分享项目Demo源码,话不多说,直接进入正题吧!老规矩,看下效果图:
如上图所示:主要涉及到的功能就是环形图和柱状图了,环形图主要分4块区域 ,点击能知道触发的那块区域,柱状图也同理。
二、自定义环形图
1.实现原理:
首先外层一个是一个灰色的圆(默认圆),这个直接用一个画笔0-360度绘制就ok了,然后再用四个画笔画4个四分之一圆,怎么画尼,我这边是利用旋转角度,分别旋转0、90、180、270度即可,接下来就是如何确定点击区域呢,其实这个也简单,通过象限原理去实现,完整代码如下
package com.*.customringchart_master;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/**
* @author xiaoyi
* @description
* 自定义环形图
* @date 2021/2/4
*/
public class CircularGraphView extends View {
private ValueAnimator valueAnimator;
private int mViewCenterX; //view宽的中心点
private int mViewCenterY; //view高的中心点
private int mRadius; //最里面白色圆的半径
private float mRingWidth; //圆环的宽度
private int mMinCircleColor; //最里面圆的颜色
private int mRingNormalColor; //默认圆环的颜色
private Paint mPaint;//默认圆环画笔
//四个圆环画笔
private Paint mPaint1;
private Paint mPaint2;
private Paint mPaint3;
private Paint mPaint4;
//4个圆环角度值
private float sweepAngle1 = 0;
private float sweepAngle2 = 0;
private float sweepAngle3 = 0;
private float sweepAngle4 = 0;
private RectF mRectF; //圆环的矩形区域
//处理点击区域
//圆周率
private static final float PI = 3.1415f;
private static final int PART_ZERO = 0;
private static final int PART_ONE = 1;
private static final int PART_TWO = 2;
private static final int PART_THREE = 3;
private static final int PART_FOUR = 4;
// 控件点击监听
private OnClickListener onClickListener;
private int mTotalRadio; //总点击区域
// 圆环文字画笔
private Paint dialWordsPaint;
public CircularGraphView(Context context) {
this(context, null);
}
public CircularGraphView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircularGraphView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularGraphView);
//最里面白色圆的半径
mRadius = a.getInteger(R.styleable.CircularGraphView_min_circle_radio, 100);
//圆环宽度
mRingWidth = a.getFloat(R.styleable.CircularGraphView_ring_width, 60);
//最里面的圆的颜色(白色)
mMinCircleColor = a.getColor(R.styleable.CircularGraphView_circle_color, context.getResources().getColor(R.color.white));
//圆环的默认颜色(圆环占据的是里面的圆的空间)
mRingNormalColor = a.getColor(R.styleable.CircularGraphView_ring_normal_color, context.getResources().getColor(R.color.color_EFF1F4));
a.recycle();
//默认圆环画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setAntiAlias(true);
//抗锯齿画笔1
mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint1.setAntiAlias(true);
//抗锯齿画笔2
mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint2.setAntiAlias(true);
//抗锯齿画笔3
mPaint3 = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint3.setAntiAlias(true);
//抗锯齿画笔4
mPaint4 = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint4.setAntiAlias(true);
//需要重写onDraw就得调用此
this.setWillNotDraw(false);
//圆环文字画笔
dialWordsPaint = new Paint();
dialWordsPaint.setAntiAlias(true);
dialWordsPaint.setStyle(Paint.Style.FILL);
dialWordsPaint.setTextSize(30.0f);
dialWordsPaint.setColor(Color.parseColor("#9E9FAF"));
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//view的宽和高,相对于父布局(用于确定圆心)
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
mViewCenterX = viewWidth / 2;
mViewCenterY = viewHeight / 2;
//画矩形
mRectF = new RectF(mViewCenterX - mRadius - mRingWidth / 2, mViewCenterY - mRadius - mRingWidth / 2,
mViewCenterX + mRadius + mRingWidth / 2, mViewCenterY + mRadius + mRingWidth / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(mMinCircleColor);
canvas.drawCircle(mViewCenterX, mViewCenterY, mRadius, mPaint);
//画文字
canvas.drawText("18点", mViewCenterX, mViewCenterY + 200, dialWordsPaint);
canvas.drawText("12点", mViewCenterX + 160, mViewCenterY, dialWordsPaint);
canvas.drawText("6点", mViewCenterX, mViewCenterY - 180, dialWordsPaint);
canvas.drawText("0点", mViewCenterX - 220, mViewCenterY, dialWordsPaint);
//画默认圆环
drawNormalRing(canvas);
//画彩色圆环
drawColorRing(canvas, mPaint1, 0f,
sweepAngle1, Color.parseColor("#EAB537"));
drawColorRing(canvas, mPaint2, -90f,
sweepAngle2, Color.parseColor("#2CCAA9"));
drawColorRing(canvas, mPaint3, -180f,
sweepAngle3, Color.parseColor("#2B6DE6"));
drawColorRing(canvas, mPaint4, -270f,
sweepAngle4, Color.parseColor("#103A87"));
}
/**
* 画默认圆环
*
* @param canvas
*/
private void drawNormalRing(Canvas canvas) {
Paint ringNormalPaint = new Paint(mPaint);
ringNormalPaint.setStyle(Paint.Style.STROKE);
ringNormalPaint.setStrokeWidth(mRingWidth);
ringNormalPaint.setColor(mRingNormalColor);//圆环默认颜色为灰色
canvas.drawArc(mRectF, 0, 360, false, ringNormalPaint);
}
/**
* 画彩色圆环
* degrees 旋转角度
* startAngle 开始角度
* sweepAngle 可以理解成结束角度
* color 圆环颜色值
*
* @param canvas
*/
private void drawColorRing(Canvas canvas, Paint paint, float degrees,
float sweepAngle, int color) {
paint.setColor(color);
Paint ringColorPaint = new Paint(paint);
ringColorPaint.setStyle(Paint.Style.STROKE);
ringColorPaint.setStrokeWidth(mRingWidth);
// ringColorPaint.setShader(new SweepGradient(mViewCenterX, mViewCenterX, color, null));
//逆时针旋转角度
canvas.rotate(degrees, mViewCenterX, mViewCenterY);
canvas.drawArc(mRectF, (float) 0.0, sweepAngle, false, ringColorPaint);
ringColorPaint.setShader(null);
}
/**
* 设置当前圆环值
*
* @param
*/
public void setAnnularData(float sweepAngle1, float sweepAngle2,
float sweepAngle3, float sweepAngle4) {
this.sweepAngle1 = sweepAngle1;
this.sweepAngle2 = sweepAngle2;
this.sweepAngle3 = sweepAngle3;
this.sweepAngle4 = sweepAngle4;
invalidate();
}
/**
* 设置当前圆环宽度比例
*
* @param minRadio 内圆半径
* @param ringWidth 圆环宽度
*/
public void setProportionData(int minRadio, float ringWidth) {
this.mRadius = minRadio;
this.mRingWidth = ringWidth;
invalidate();
}
/**
* 饼图touch事件
* 获取触摸位置计算属于哪个区域
*
* @param
* @return
*/
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX() - mViewCenterX;
float y = event.getY() - mViewCenterY;
whichZone(x,y);
}
return super.onTouchEvent(event);
}
/**
* 判断点击了圆的哪个区域
* @param x
* @param y
*/
private void whichZone(float x, float y) {
// 简单的象限点处理
// 第一象限在右下角,第二象限在左下角,代数里面的是逆时针,这里是顺时针
if(x > 0 && y > 0) {
// 点击事件
if (onClickListener != null) {
onClickListener.onClick(PART_ZERO);
}
} else if(x > 0 && y < 0) {
// 点击事件
if (onClickListener != null) {
onClickListener.onClick(PART_THREE);
}
} else if(x < 0 && y < 0) {
// 点击事件
if (onClickListener != null) {
onClickListener.onClick(PART_TWO);
}
} else if(x < 0 && y > 0) {
// 点击事件
if (onClickListener != null) {
onClickListener.onClick(PART_ONE);
}
}
}
/**
* 设置点击监听
*
* @param onClickListener 点击回调接口
*/
public void setOnClickListener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
/**
* 点击回调接口
*/
public interface OnClickListener {
/**
* 点击回调方法
*
* @param region 区域类型
*/
void onClick(int region);
}
}
三、自定义柱状图
package com.*.customringchart_master;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* @author xiaoyi
* @description
* 自定义柱状图
* @date 2021/2/4
*/
public class HistogramView extends FrameLayout {
protected int defaultBorderColor = Color.argb(255, 217, 217, 217);
protected int titleTextColor = Color.argb(255, 217, 217, 217);
protected int labelTextColor;
protected int mTitleTextSize = 42;
protected int mLabelTextSize = 20;
protected String mTitle;
private int mWidth;
private int mHeight;
private int mLeftTextSpace;
private int mBottomTextSpace;
private int mTopTextSpace;
protected Paint mBorderLinePaint;
private Double maxData=0.0;
private List mDatas;
/**
* 备注文本画笔
*/
private Paint mTextPaint;
/**
* 标题文本画笔
*/
private Paint mTitleTextPaint;
private BaseChart baseChartView;
public HistogramView(@NonNull Context context) {
super(context);
init(context, null);
}
public HistogramView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public HistogramView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HistogramView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
@SuppressLint("CustomViewStyleable")
private void init(Context context, AttributeSet attrs) {
mDatas = new ArrayList<>();
TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.barCharts);
defaultBorderColor = t.getColor(R.styleable.barCharts_borderColor, defaultBorderColor);
titleTextColor = t.getColor(R.styleable.barCharts_titleTextColor, Color.GRAY);
mTitleTextSize = (int) t.getDimension(R.styleable.barCharts_titleTextSize, mTitleTextSize);
mLabelTextSize = (int) t.getDimension(R.styleable.barCharts_labelTextSize, mLabelTextSize);
labelTextColor = t.getColor(R.styleable.barCharts_labelTextColor, Color.GRAY);
mLeftTextSpace = (int) t.getDimension(R.styleable.barCharts_leftTextSpace, 30);
mBottomTextSpace = (int) t.getDimension(R.styleable.barCharts_bottomTextSpace, 20);
mTopTextSpace = (int) t.getDimension(R.styleable.barCharts_topTextSpace, 70); //间距
mTitle = t.getString(R.styleable.barCharts_title);
t.recycle();
mBorderLinePaint = generatePaint();
mBorderLinePaint.setColor(defaultBorderColor);
mBorderLinePaint.setStrokeWidth(dp2px(context, 1));
mTextPaint = generatePaint();
mTextPaint.setColor(labelTextColor);
mTextPaint.setTextSize(mLabelTextSize);
mTitleTextPaint = generatePaint();
mTitleTextPaint.setColor(titleTextColor);
mTitleTextPaint.setTextSize(mTitleTextSize);
baseChartView = new BaseChart(context, attrs);
LayoutParams parames = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
parames.setMargins(mLeftTextSpace, mTopTextSpace, mLeftTextSpace, 0);
baseChartView.setLayoutParams(parames);
baseChartView.setBottomDrawPadding(mBottomTextSpace);
baseChartView.setLeftDrawPadding(mLeftTextSpace);
baseChartView.setTopDrawPadding(mTopTextSpace);
addView(baseChartView);
}
private Paint generatePaint() {
Paint m = new Paint();
m.setAntiAlias(true);
m.setStyle(Paint.Style.STROKE);
return m;
}
private void setMaxData() {
if (mDatas.size()>0){
this.maxData = Collections.max(mDatas);
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mTitle != null) {
canvas.drawText(mTitle, mWidth / 2 - mTitleTextPaint.measureText(mTitle) / 2,
mTopTextSpace - mTitleTextSize, mTitleTextPaint);
}
canvas.translate(mLeftTextSpace, mHeight - mBottomTextSpace);
}
public void setDatas(List mDatas, List mDescribe,boolean isAnimation) {
this.mDatas = mDatas;
setMaxData();
baseChartView.setDatas(mDatas, mDescribe,isAnimation);
}
//柱状图item点击事件
public void setOnItemClick(BaseChart.setOnRangeBarItemClickListener clickListener) {
baseChartView.setOnRangeBarItemClickListener(clickListener);
}
public void addEndMoreData(List mDatas, List mDesciption) {
baseChartView.addEndMoreData(mDatas, mDesciption);
}
public void addStartMoreData(List mDatas, List mDesciption) {
baseChartView.addStartMoreData(mDatas,mDesciption);
}
public static int dp2px(Context context, int dpValue) {
return (int) context.getResources().getDisplayMetrics().density * dpValue;
}
}
package com.*.customringchart_master;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author xiaoyi
* @description
* 自定义柱状图
* @date 2021/2/4
*/
public class BaseChart extends View {
protected List mDatas;
protected List mDescription;
//柱状图画笔
protected Paint mDataLinePaint;
protected int defaultLineColor = Color.parseColor("#2B6DE6");
protected int descriptionColor;
protected int dataColor;
private int mWidth;
private int mHeight;
private int mShowNumber;
private float perBarW;
private Double maxData = 0.0;
private int mMaxScrollx;
protected int defaultBorderColor = Color.argb(255, 217, 217, 217);
protected Paint mBorderLinePaint;
//x轴描述文字画笔
protected Paint mTextPaint;
protected int descriptionTextSize;
protected int dataTextSize;
private int mBottomPadding;
private int mLeftPadding;
private int mTopPadding;
protected float scale = 0.5f;
protected boolean canClickAnimation = false;
protected ValueAnimator animator;
// 柱状图控件点击监听 0.0
private setOnRangeBarItemClickListener onRangeBarItemClickListener;
/* 用户点击到了无效位置 */
public static final int INVALID_POSITION = -1;
/* 辅助计算柱宽,表示一个条目的宽度,包括柱子和空余部分 */
private float mItemBarWidth = 0;
private Context mContext;
public BaseChart(Context context) {
super(context);
init(context, null);
}
public BaseChart(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
@SuppressLint("CustomViewStyleable")
private void init(Context context, AttributeSet attrs) {
mContext = context;
initAnimation();
TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.barCharts);
defaultBorderColor = t.getColor(R.styleable.barCharts_borderColor, defaultBorderColor);
descriptionTextSize = (int) t.getDimension(R.styleable.barCharts_labelTextSize, 30);
dataTextSize = (int) t.getDimension(R.styleable.barCharts_dataTextSize, 20);
descriptionColor = t.getColor(R.styleable.barCharts_descriptionTextColor, Color.GRAY);
dataColor = t.getColor(R.styleable.barCharts_dataTextColor, Color.GRAY);
mShowNumber = t.getInteger(R.styleable.barCharts_barShowNumber, 4);
canClickAnimation = t.getBoolean(R.styleable.barCharts_isClickAnimation, false);
t.recycle();
mDatas = new ArrayList<>();
mDescription = new ArrayList<>();
mDataLinePaint = new Paint();
mDataLinePaint.setAntiAlias(true);
mDataLinePaint.setColor(defaultLineColor);
mDataLinePaint.setStyle(Paint.Style.STROKE);
mBorderLinePaint = new Paint();
mBorderLinePaint.setColor(defaultBorderColor);
mBorderLinePaint.setStyle(Paint.Style.STROKE);
mBorderLinePaint.setStrokeWidth(dp2px(5));
mBorderLinePaint.setAntiAlias(true);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.GRAY);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTextSize(dp2pxTo(context,14.0f));
}
public BaseChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
setDataLineWidth();
}
private void setDataLineWidth() {
if (mDatas.size() > 0) {
//设置柱状图宽度
mDataLinePaint.setStrokeWidth(15);
mMaxScrollx = (mWidth / mShowNumber) * mDatas.size() - mWidth;
//计算ITEM宽度
mItemBarWidth = mWidth / mDatas.size();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
perBarW = mWidth / mShowNumber;
canvas.translate(0, mHeight - mBottomPadding);
setMaxData();
canvas.drawLine(0, 0, mMaxScrollx + mWidth, 0, mBorderLinePaint);
for (int i = 0; i < mDatas.size(); i++) {
String perData = String.valueOf(Math.round(scale < 1 ? Math.round(mDatas.get(i) * scale) : mDatas.get(i)));
float x = (i + 0.5f) * perBarW;
float y = (float) ((mHeight - mTopPadding - mBottomPadding) / maxData * mDatas.get(i));
canvas.drawLine(x, 0, x, -y * scale, mDataLinePaint);
mTextPaint.setTextSize(dataTextSize);
mTextPaint.setColor(dataColor);
if (Integer.parseInt(perData) != 0) {
canvas.drawText(perData + "次",
x - mTextPaint.measureText(perData) / 2,
-y * scale - dataTextSize,
mTextPaint);
}
mTextPaint.setTextSize(descriptionTextSize);
mTextPaint.setColor(descriptionColor);
}
//绘制描文字
for (int i = 0; i < mDescription.size(); i++) {
float x = (i + 0.5f) * perBarW;
canvas.drawText(mDescription.get(i),
x - mTextPaint.measureText(mDescription.get(i)) / 2,
descriptionTextSize * 2,
mTextPaint);
}
}
public void startCliclkAnimation() {
// if (canClickAnimation) {
animator.start();
// }
}
private void initAnimation() {
animator = ValueAnimator.ofFloat(0.2f, 1);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(600);
animator.setRepeatCount(0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scale = (float) animation.getAnimatedValue();
postInvalidate();
}
});
}
public void setBottomDrawPadding(int bottomy) {
mBottomPadding = bottomy;
}
public void setLeftDrawPadding(int left) {
mLeftPadding = left;
}
public void setTopDrawPadding(int left) {
mTopPadding = left;
}
private void setMaxData() {
if (mDatas.size() > 0) {
this.maxData = Collections.max(mDatas);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int position = identifyWhickItemClick(event.getX(), event.getY());
if (position != INVALID_POSITION && onRangeBarItemClickListener != null) {
startCliclkAnimation();
onRangeBarItemClickListener.onItemClick(position);
}
}
return super.onTouchEvent(event);
}
/**
* 根据点击的手势位置识别是第几个柱图被点击
*
* @param x
* @param y
* @return -1时表示点击的是无效位置
*/
private int identifyWhickItemClick(float x, float y) {
float leftx = 0;
float rightx = 0;
for (int i = 0; i < mDatas.size(); i++) {
leftx = i * mItemBarWidth;
rightx = (i + 1) * mItemBarWidth;
if (x < leftx) {
break;
}
if (leftx <= x && x <= rightx && mDatas.get(i) != 0.0) {
return i;
}
}
return INVALID_POSITION;
}
/**
* 设置点击监听
*
* @param onClickListener 点击回调接口
*/
public void setOnRangeBarItemClickListener(setOnRangeBarItemClickListener onClickListener) {
this.onRangeBarItemClickListener = onClickListener;
}
/**
* 点击回调接口
*/
public interface setOnRangeBarItemClickListener {
/**
* 点击回调方法
*
* @param position 点击的下标
*/
void onItemClick(int position);
}
public void setDatas(List mDatas, List mDescribe, boolean isAnimation) {
this.mDatas.clear();
this.mDatas.addAll(mDatas);
this.mDescription = mDescribe;
setDataLineWidth();
if (isAnimation) {
animator.start();
} else {
scale = 1;
postInvalidate();
}
}
public void addEndMoreData(List mDatas, List mDesciption) {
this.mDatas.addAll(mDatas);
this.mDescription.addAll(mDesciption);
setDataLineWidth();
scale = 1;
postInvalidate();
}
private int startX = 0;
public void addStartMoreData(List mDatas, List mDesciption) {
mDatas.addAll(this.mDatas);
mDesciption.addAll(this.mDescription);
this.mDatas.clear();
this.mDatas.addAll(mDatas);
this.mDescription.clear();
this.mDescription.addAll(mDesciption);
startX = (mWidth / mShowNumber) * mDatas.size();
setDataLineWidth();
postInvalidate();
}
protected int dp2px(int dpValue) {
return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
}
public static float dp2pxTo(Context context,float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics());
}
}
四、布局文件代码
总结:
1.以上就是环形图和柱状图所以实现代码了,柱状图我这边直接贴代码了,代码不难应该很好理解,
这里我要强调几点,环形图上面四个文字,坐标我是写死的,正常来说 需要动态计算的,还有一个自定义环形图手机适配的问题,打个比方,我在720手机上 圆的半径100和圆环宽度给的60刚刚好,但是分辨高的手机上显示的比例却小了,博主的解决办法:首先获取手机分辨率宽高,公式:60 / 720.0 * width+40 然后重新调用setProportionData方法设置一下半径和圆环宽度即可。
2.毕竟代码都需要慢慢完善,环形图动画暂未添加 ,需要自行实现。
3.最后喜欢该文章的朋友,欢迎点赞收藏哈,若有笔误的地方,请多多指教,勿喷!