项目中需要实现一个一级佣金以及二级佣金的比例示意图。看下设计稿
一、分析
一开始分析的是,先绘制完圆环,然后再去找到各自圆环的中心点,进行做切线,做中垂线出来绘制折线,然后绘制佣金比例以及显示。后面发现这么计算太麻烦了。索性就定死那个两个折线图以及比例显示。大概的思路如下图。会进行一系列简化。
1、简化点,把折线显示部分设置成了固定,然后圆环在动。
2、因为我们使用canvas绘制圆环或者圆的时候,其实是在一个矩形区域中绘制的,所以我们简化了折线那一部分,就是圆距离矩形左下(右上)角的距离,然后水平方向就是raduis的长度,半径长度。
3、可以看到设计稿纸上我们有一个圆弧之间的一个间距,与底色相同颜色为了区分两个圆环。这里可以采用绘制完圆环后在上层重新绘制那调白线,那就需要计算各点坐标绘制两条折线,我后面一想,还可以采用在同一个rectf区域中覆盖一个相同半径的空心圆环,ok,顿时没有了难点有木有。实心嵌套空心圆环实现两个圆环之间的
4、看下我实现的最终效果图
二、计算各点坐标
注意,我们的坐标是重左上角开始的。。。往下或者往右走
这里再继续解释下,绘制圆弧的角度问题吧(顺时针旋转)如下图
看下绘制圆弧需要传入的参数
drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
@NonNull Paint paint)
oval圆弧切过的矩形区域
startAngle开始角度
sweepAngle扫过的角度(需要绘制的角度)
useCenter是否要连着圆心绘制
paint画笔
圆心坐标(2mRaduis,2mRaduis)
矩形区域RectF坐标(mRaduis, mRaduis, mRaduis * 3, mRaduis * 3)
左下角圆弧起始角度,扫过角度(第一佣金比例)
startAngle=135 - (mFirstPoint / 100 * 360) / 2
sweepAngle=(mFirstPoint / 100 * 360)
右上角圆弧起始角度,扫过角度(第二佣金比例)
startAngle=315 - (360 - mFirstPoint / 100 * 360) / 2
sweepAngle=(360 - mFirstPoint / 100 * 360)
左下角折线
canvas.drawLine((float) (1 - Math.sqrt(2) / 2) * mRaduis + mRaduis, (float) (1 + Math.sqrt(2) / 2) * mRaduis + mRaduis, mRaduis, 3 * mRaduis, mTextPaint);
canvas.drawLine(mRaduis, 2 * mRaduis + mRaduis, 0, 3 * mRaduis, mTextPaint);
右下角折线
canvas.drawLine((float) (2 + Math.sqrt(2) / 2) * mRaduis, (float) (2 * mRaduis - Math.sqrt(2) / 2 * mRaduis), 3 * mRaduis, mRaduis, mTextPaint);
canvas.drawLine(3 * mRaduis, mRaduis, 4 * mRaduis, mRaduis, mTextPaint);
三、实现功能代码
1、attr文件中的自定义属性
<!--圆环饼图-->
<declare-styleable name="CircleChart">
<attr name="mRaduis" format="dimension" />
<attr name="mFirstPoint" format="float" />
<attr name="mLinewith" format="dimension" />
<attr name="mLineColor" format="color" />
<attr name="mFirstPointColor" format="color" />
<attr name="mSecondPointColor" format="color" />
<attr name="mPointTextsize" format="dimension" />
<attr name="mStokeColor" format="color" />
<attr name="mTextColor" format="color" />
</declare-styleable>
2、自定义饼图控件:CircleChart.java
package com.xx.xx.widget;
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.util.TypedValue;
import android.widget.TextView;
import com.coofond.carservices.R;
/**
* @description: 我的分享饼图
* @Author zsj on 2017/2/21 15:24.
*/
public class CircleChart extends TextView {
/**
* 饼图半径
*/
private int mRaduis;
/**
* 一级佣金颜色
*/
private int mFirstPointColor;
/**
* 二级佣金颜色
*/
private int mSecondPointColor;
/**
* 第一佣金比例
*/
private float mFirstPoint;
/**
* 饼图上的字体大小
*/
private int mPointTextSize;
/**
* 线条宽度
*/
private int mLineWith;
/**
* 线条颜色
*/
private int mLineColor;
/**
* 填充的画笔
*/
private Paint mPaint;
/**
* 用来描边的画笔
*/
private Paint mStokePaint;
/**
* 描边颜色
*/
private int mStokeColor;
/**
* 绘制文字的画笔
*/
private Paint mTextPaint;
/**
* 绘制文字的颜色
*/
private int mTextColor;
/**
* @param mFirstPoint 设置第一佣金比例
*/
public void setmFirstPoint(float mFirstPoint) {
this.mFirstPoint = mFirstPoint;
}
public CircleChart(Context context) {
this(context, null);
}
public CircleChart(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleChart(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
* 获取我们的自定义属性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CircleChart, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CircleChart_mRaduis:
mRaduis = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()));
break;
case R.styleable.CircleChart_mFirstPoint:
mFirstPoint = a.getFloat(attr, 50);
break;
case R.styleable.CircleChart_mLinewith:
mLineWith = a.getDimensionPixelOffset(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
break;
case R.styleable.CircleChart_mLineColor:
mLineColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CircleChart_mFirstPointColor:
mFirstPointColor = a.getColor(attr, Color.BLUE);
break;
case R.styleable.CircleChart_mSecondPointColor:
mSecondPointColor = a.getColor(attr, Color.RED);
break;
case R.styleable.CircleChart_mPointTextsize:
mPointTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics()));
break;
case R.styleable.CircleChart_mStokeColor:
mStokeColor = a.getColor(attr, Color.WHITE);
break;
case R.styleable.CircleChart_mTextColor:
mTextColor = a.getColor(attr, Color.BLACK);
break;
}
}
a.recycle();
//初始化paint
mPaint = new Paint();
mStokePaint = new Paint();
mTextPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
mPaint.setAntiAlias(true);//消除锯齿
mStokePaint.setAntiAlias(true);//消除锯齿
mTextPaint.setAntiAlias(true);//消除锯齿
mStokePaint.setStyle(Paint.Style.STROKE);
mStokePaint.setStrokeWidth(mLineWith / 2);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mFirstPointColor);
mStokePaint.setColor(mStokeColor);
RectF oval = new RectF(mRaduis, mRaduis, mRaduis * 3, mRaduis * 3);
//绘制实心圆弧
canvas.drawArc(oval, 135 - (mFirstPoint / 100 * 360) / 2, (mFirstPoint / 100 * 360), true, mPaint);
//绘制与底色相同的圆环
canvas.drawArc(oval, 135 - (mFirstPoint / 100 * 360) / 2, (mFirstPoint / 100 * 360), true, mStokePaint);
mPaint.setColor(mSecondPointColor);
//绘制实心圆弧
canvas.drawArc(oval, 315 - (360 - mFirstPoint / 100 * 360) / 2, (360 - mFirstPoint / 100 * 360), true, mPaint);
//绘制与底色相同的圆环
canvas.drawArc(oval, 315 - (360 - mFirstPoint / 100 * 360) / 2, (360 - mFirstPoint / 100 * 360), true, mStokePaint);
mTextPaint.setColor(mTextColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setStrokeWidth(1);
//绘制折线
canvas.drawLine((float) (1 - Math.sqrt(2) / 2) * mRaduis + mRaduis, (float) (1 + Math.sqrt(2) / 2) * mRaduis + mRaduis, mRaduis, 3 * mRaduis, mTextPaint);
canvas.drawLine(mRaduis, 2 * mRaduis + mRaduis, 0, 3 * mRaduis, mTextPaint);
canvas.drawLine((float) (2 + Math.sqrt(2) / 2) * mRaduis, (float) (2 * mRaduis - Math.sqrt(2) / 2 * mRaduis), 3 * mRaduis, mRaduis, mTextPaint);
canvas.drawLine(3 * mRaduis, mRaduis, 4 * mRaduis, mRaduis, mTextPaint);
//绘制文字
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mPointTextSize);
canvas.drawText("一级佣金", 0, 3 * mRaduis - mRaduis / 20, mTextPaint);
canvas.drawText("二级佣金", 4 * mRaduis - mTextPaint.measureText("二级佣金"), mRaduis - mRaduis / 20, mTextPaint);
mTextPaint.setColor(mFirstPointColor);
canvas.drawText((int) mFirstPoint + "%", 0, 3 * mRaduis + mRaduis / 20 + mPointTextSize, mTextPaint);
mTextPaint.setColor(mSecondPointColor);
canvas.drawText((int) (100 - mFirstPoint) + "%", 4 * mRaduis - mTextPaint.measureText("75%"), mRaduis + mRaduis / 20 + mPointTextSize, mTextPaint);
}
}
3、xml文件引用
<com.xx.xx.widget.CircleChart
android:id="@+id/cir_point"
android:layout_width="240dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:layout_marginBottom="20px"
android:layout_marginTop="-80px"
app:mFirstPoint="10"
app:mFirstPointColor="@color/textorange"
app:mLinewith="5dp"
app:mPointTextsize="14sp"
app:mRaduis="60dp"
app:mSecondPointColor="@color/orange"
app:mStokeColor="@color/activitycolor"
app:mTextColor="@color/textcolordark" />
4、activity中调用
cirPoint.setmFirstPoint(60);//获取这个控件直接set...就这么简单