attrs内容
<declare-styleable name="MyRingView">
<!-- 圆环宽度 -->
<attr name="ringWidth" format="float" />
<!-- 圆环的默认颜色 -->
<attr name="ringNormalColor" format="color"/>
</declare-styleable>
代码
public class MyRingView extends View {
private Paint dataPaint, assetsPaint;
private RectF rectF;
//
private ArrayList<Paint> paints;
//数据, key - 颜色值, value - 数值
private ArrayMap<Integer, Integer> dataMap;
private ArrayList<Integer> paintColor;
private ArrayList<Integer> paintData;
private ArrayList<Path> paths;
private ArrayList<Region> regions;
//圆环宽度
private float ringWidth;
//圆环默认颜色
private int ringNormalColor;
//圆环起始角
private int ringStartAngle = 0, startAngle;
//圆环角度
private int ringAngle = 360;
//圆环 宽 高
private int viewWidth, viewHeight;
//是否可以旋转
private boolean rotate = false;
private setOnClickListener listener;
public void setListener(setOnClickListener listener) {
this.listener = listener;
}
public MyRingView(Context context) {
this(context, null);
}
public MyRingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* Paint.ANTI_ALIAS_FLAG :抗锯齿标志
* Paint.FILTER_BITMAP_FLAG : 使位图过滤的位掩码标志
* Paint.DITHER_FLAG : 使位图进行有利的抖动的位掩码标志
* Paint.UNDERLINE_TEXT_FLAG : 下划线
* Paint.STRIKE_THRU_TEXT_FLAG : 中划线
* Paint.FAKE_BOLD_TEXT_FLAG : 加粗
* Paint.LINEAR_TEXT_FLAG : 使文本平滑线性扩展的油漆标志
* Paint.SUBPIXEL_TEXT_FLAG : 使文本的亚像素定位的绘图标志
* Paint.EMBEDDED_BITMAP_TEXT_FLAG : 绘制文本时允许使用位图字体的绘图标志
*/
@SuppressLint("UseSparseArrays")
public MyRingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyRingView, defStyleAttr, 0);
ringWidth = ta.getFloat(R.styleable.MyRingView_ringWidth, 50);
ringNormalColor = ta.getColor(R.styleable.MyRingView_ringNormalColor, context.getResources().getColor(R.color.colorTran));
ta.recycle();
dataPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dataPaint.setAntiAlias(true);
dataPaint.setStyle(Paint.Style.STROKE);
dataPaint.setStrokeWidth(ringWidth);
assetsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
assetsPaint.setAntiAlias(true);
assetsPaint.setStyle(Paint.Style.STROKE);
assetsPaint.setStrokeWidth(ringWidth);
setWillNotDraw(false);
paints = new ArrayList<>();
paintColor = new ArrayList<>();
paintData = new ArrayList<>();
paths = new ArrayList<>();
regions = new ArrayList<>();
dataMap = new ArrayMap<>();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
enter = width / 2;
setMeasuredDimension(width, width);
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
viewWidth = getWidth();
viewHeight = getHeight();
rectF = new RectF(
ringWidth / 2,
ringWidth / 2,
viewWidth - ringWidth / 2,
viewHeight - ringWidth / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRing(canvas);
}
/**
* MotionEvent.ACTION_DOWN:当屏幕检测到第一个触点按下之后就会触发到这个事件。
* MotionEvent.ACTION_MOVE:当触点在屏幕上移动时触发,触点在屏幕上停留也是会触发的,主要是由于它的灵敏度很高,
* 而我们的手指又不可能完全静止(即使我们感觉不到移动,但其实我们的手指也在不停地抖动)。
* MotionEvent.ACTION_POINTER_DOWN:当屏幕上已经有触点处于按下的状态的时候,再有新的触点被按下时触发。
* MotionEvent.ACTION_POINTER_UP:当屏幕上有多个点被按住,松开其中一个点时触发(即非最后一个点被放开时)触发。
* MotionEvent.ACTION_UP:当触点松开时被触发。
* MotionEvent.ACTION_OUTSIDE: 表示用户触碰超出了正常的UI边界.
* MotionEvent.ACTION_SCROLL:android3.1引入,非触摸滚动,主要是由鼠标、滚轮、轨迹球触发。
* MotionEvent.ACTION_CANCEL:不是由用户直接触发,由系统在需要的时候触发,例如当父view通过使函数
*/
private int x, y;
private float enter;
private int level, number;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = (int) event.getX();
y = (int) event.getY();
for (int i = 0; i < regions.size(); i++) {
if (regions.get(i).contains(x, y)) {
if (number < 100){
if (i == level - 1){
Toast.makeText(getContext(), "无数据", Toast.LENGTH_SHORT).show();
}else {
listener.onClickListener(i);
}
}
if(number >= 100){
listener.onClickListener(i);
}
}
}
break;
case MotionEvent.ACTION_MOVE:
int x1 = (int) event.getX();
int y1 = (int) event.getY();
float k1 = (x - enter) / (y - enter);
float k2 = (x1 - enter) / (y1 - enter);
if (ringStartAngle >= 360 || ringStartAngle <= -360) {
ringStartAngle = 0;
}
if (k1 > k2) { //顺时针
ringStartAngle = ringStartAngle + 3;
} else { //逆时针
ringStartAngle = ringStartAngle - 3;
}
x = (int) event.getX();
y = (int) event.getY();
if (rotate){
invalidate();
}
break;
case MotionEvent.ACTION_UP:
// invalidate();
break;
}
return true;
}
/**
* path.arcTo 添加弧形
* path.addOval 添加扇形
*/
private void drawRing(Canvas canvas) {
paintColor.clear();
paintData.clear();
paints.clear();
paths.clear();
regions.clear();
startAngle = ringStartAngle;
for (Integer integer : dataMap.keySet()) {
paintColor.add(integer);
paintData.add(dataMap.get(integer));
paints.add(assetsPaint);
paths.add(new Path());
regions.add(new Region());
}
if (dataMap.size() <= 0) {
dataPaint.setColor(ringNormalColor);
canvas.drawArc(rectF, startAngle, ringAngle, false, dataPaint);
} else {
level = paintColor.size();
number = 0;
for (int i = 0; i < level; i++) {
number += paintData.get(i);
}
if (number < 100) {
paintColor.add(Color.parseColor("#bbbbbb"));
paintData.add(100 - number);
paints.add(assetsPaint);
paths.add(new Path());
regions.add(new Region());
}
level = paintColor.size();
for (int i = 0; i < level; i++) {
paints.get(i).setColor(paintColor.get(i));
if (i == level - 1) {
canvas.drawArc(rectF, startAngle, ringAngle - startAngle + ringStartAngle, false, paints.get(i));
paths.get(i).arcTo(rectF, startAngle, ringAngle - startAngle + ringStartAngle);
regions.get(i).setPath(paths.get(i), new Region((int) rectF.left, (int) rectF.top,
(int) rectF.right, (int) rectF.bottom));
} else {
canvas.drawArc(rectF, startAngle, Math.round((float) (paintData.get(i) * 3.6)), false, paints.get(i));
paths.get(i).arcTo(rectF, startAngle, Math.round((float) (paintData.get(i) * 3.6)));
regions.get(i).setPath(paths.get(i), new Region((int) rectF.left, (int) rectF.top,
(int) rectF.right, (int) rectF.bottom));
startAngle += Math.round((float) (paintData.get(i) * 3.6));
}
}
}
}
//设置数据
public void setMapData(Map map){
dataMap.clear();
dataMap.putAll(map);
}
//设置是否旋转
public void setRotate(boolean rot){
rotate = rot;
}
public interface setOnClickListener{
void onClickListener(int index);
}
}