package com.wuyzh.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/***
* 1/4扇形进度条
* */
public class PieChartSeekBar extends View {
//饼状图半径
private float mRadius = DensityUtils.dip2px(getContext(), 320);
private RectF mSectorRectF = new RectF();
//扇形外圈宽度
private float mRadiusOutlineWidth = 5f;
private RectF mIncludeOutLineRectF = new RectF();
//初始画弧所在的角度
private float mCurrentDegree = 135f;
//空白间隙占整个圆形的大小比例
private double mSpacePercent = 0.002f;
//每块扇形占整个圆的大小比例
private double mSectorPercent;
//扇形块个数
private int mSize = 8;
//当前进度
private int mCurrentLevel = 4;
//画笔
private Paint mPaint;
private Xfermode mDstOutXfermode;
private PorterDuff.Mode mDstOutPorterDuffMode = PorterDuff.Mode.DST_OUT;
private Xfermode mSrcOverXfermode;
private PorterDuff.Mode mSrcOverPorterDuffMode = PorterDuff.Mode.SRC_OVER;
//设置监听回调
private OnPieChartSeekBarChangeListener mOnPieChartSeekBarChangeListener;
public PieChartSeekBar(Context context) {
super(context);
init();
}
public PieChartSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PieChartSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//初始化画笔和效果动画
private void init() {
mDstOutXfermode = new PorterDuffXfermode(mDstOutPorterDuffMode);
mSrcOverXfermode = new PorterDuffXfermode(mSrcOverPorterDuffMode);
initRectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mSectorPercent = (0.25 - (mSize-1)*mSpacePercent)/mSize;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int saveCount = canvas.saveLayer(mIncludeOutLineRectF, mPaint, Canvas.ALL_SAVE_FLAG);
mCurrentDegree = 135;
float pieSweep;
for (int i = 1; i <= mSize; i++){
if (i <= mCurrentLevel){
//画外部进度指示线 颜色:0xFFcca267
pieSweep = (float) (mSectorPercent *360);
mPaint.setShader(null);
mPaint.setColor(0xFFcca267);
canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
//切掉内部圆
mPaint.setColor(Color.BLACK);
mPaint.setXfermode(mDstOutXfermode);
canvas.drawArc(mSectorRectF, mCurrentDegree-0.002f*360, pieSweep+0.003f*360,true, mPaint);
mPaint.setXfermode(null);
//画扇形 颜色:0xFF02DAFD
RadialGradient gradient =new RadialGradient(mRadius,mRadius,mRadius-mRadiusOutlineWidth,new int[]{Color.TRANSPARENT,Color.TRANSPARENT,0xFF02DAFD},new float[]{0,(mRadius-100)/mRadius,1},Shader.TileMode.MIRROR);
mPaint.setShader(gradient);
mPaint.setXfermode(mSrcOverXfermode);
canvas.drawArc(mSectorRectF, mCurrentDegree, pieSweep, true, mPaint);
mPaint.setXfermode(null);
mCurrentDegree = mCurrentDegree + pieSweep;
}else {
//画外部进度指示线 颜色:0xFF65fbe4
pieSweep = (float) (mSectorPercent *360);
mPaint.setShader(null);
mPaint.setColor(0xFF65fbe4);
canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
//切掉内部圆
mPaint.setColor(Color.BLACK);
mPaint.setXfermode(mDstOutXfermode);
canvas.drawArc(mSectorRectF, mCurrentDegree-0.002f*360, pieSweep+0.003f*360,true, mPaint);
mPaint.setXfermode(null);
//画扇形 颜色:0xFFFFFFFF
RadialGradient gradient =new RadialGradient(mRadius,mRadius,mRadius-mRadiusOutlineWidth,new int[]{Color.TRANSPARENT,Color.TRANSPARENT,0xFFFFFFFF},new float[]{0,(mRadius-100)/mRadius,1},Shader.TileMode.MIRROR);
mPaint.setShader(gradient);
mPaint.setXfermode(mSrcOverXfermode);
canvas.drawArc(mSectorRectF, mCurrentDegree, pieSweep, true, mPaint);
mPaint.setXfermode(null);
mCurrentDegree = mCurrentDegree + pieSweep;
}
//画透明间隔
if (i != mSize){
pieSweep = (float) (mSpacePercent * 360);
mPaint.setColor(Color.TRANSPARENT);
canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
mCurrentDegree = mCurrentDegree + pieSweep;
}
}
//切掉内部圆
mPaint.setShader(null);
mPaint.setColor(Color.BLACK);
mPaint.setXfermode(mDstOutXfermode);
canvas.drawCircle(mRadius, mRadius, mRadius-100, mPaint);
mPaint.setXfermode(null);
canvas.restoreToCount(saveCount);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int length = (int) (2 * mRadius);
setMeasuredDimension(length, length);
}
/**
* 初始化绘制弧形所在矩形的四点坐标
**/
private void initRectF() {
mSectorRectF.left = 0 +mRadiusOutlineWidth;
mSectorRectF.top = 0 + mRadiusOutlineWidth;
mSectorRectF.right = 2 * mRadius - mRadiusOutlineWidth;
mSectorRectF.bottom = 2 * mRadius - mRadiusOutlineWidth;
mIncludeOutLineRectF.left = 0;
mIncludeOutLineRectF.top = 0;
mIncludeOutLineRectF.right = 2 * mRadius;
mIncludeOutLineRectF.bottom = 2 * mRadius;
}
private int mTouchPosition;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchPosition = doOnSpecialTypeClick(event);
if (mTouchPosition == -1){
return false;
}else {
mCurrentLevel = mTouchPosition;
if (mOnPieChartSeekBarChangeListener != null){
mOnPieChartSeekBarChangeListener.onStartTrackingTouch(this);
}
invalidate();
return true;
}
case MotionEvent.ACTION_MOVE:
mTouchPosition = doOnSpecialTypeClick(event);
if (mTouchPosition != -1){
mCurrentLevel = mTouchPosition;
if (mOnPieChartSeekBarChangeListener != null){
mOnPieChartSeekBarChangeListener.onProgressChanged(this,mCurrentLevel,true);
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mOnPieChartSeekBarChangeListener != null){
mOnPieChartSeekBarChangeListener.onStopTrackingTouch(this);
}
break;
}
return super.onTouchEvent(event);
}
public int getProgress(){
return mCurrentLevel;
}
public void setProgress(int level){
mCurrentLevel = level;
if (mOnPieChartSeekBarChangeListener != null){
mOnPieChartSeekBarChangeListener.onProgressChanged(this,mCurrentLevel,true);
}
invalidate();
}
private int doOnSpecialTypeClick(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
double alfa = 0;
//点击的位置到圆心距离的平方
double distance = Math.pow(eventX - mRadius, 2) + Math.pow(eventY - mRadius, 2);
//判断点击的坐标是否在环内
if (distance < Math.pow(mRadius, 2) && distance > Math.pow(0.72 * mRadius, 2)) {
int which = touchOnWhichPart(event);
switch (which) {
case PART_ONE:
alfa = Math.atan2(eventX - mRadius, mRadius - eventY) * 180 / PI;
break;
case PART_TWO:
alfa = Math.atan2(eventY - mRadius, eventX - mRadius) * 180 / PI + 90;
break;
case PART_THREE:
alfa = Math.atan2(mRadius - eventX, eventY - mRadius) * 180 / PI + 180;
break;
case PART_FOUR:
alfa = Math.atan2(mRadius - eventY, mRadius - eventX) * 180 / PI + 270;
break;
}
}
int position = (int) Math.ceil((alfa-225)/(90.0/mSize));
if (0 <= position&& position <= mSize){
return position;
}else {
return -1;
}
}
/**
* 4 | 1
* -----|-----
* 3 | 2
* 圆被分成四等份,判断点击在园的哪一部分
*/
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 static final float PI = 3.1415f;
private int touchOnWhichPart(MotionEvent event) {
if (event.getX() > mRadius) {
if (event.getY() > mRadius) return PART_TWO;
else return PART_ONE;
} else {
if (event.getY() > mRadius) return PART_THREE;
else return PART_FOUR;
}
}
public void setOnPieChartSeekBarChangeListener(OnPieChartSeekBarChangeListener onPieChartSeekBarChangeListener){
mOnPieChartSeekBarChangeListener = onPieChartSeekBarChangeListener;
}
public interface OnPieChartSeekBarChangeListener {
void onProgressChanged(PieChartSeekBar pieChartSeekBar, int level, boolean isFromUser);
void onStartTrackingTouch(PieChartSeekBar pieChartSeekBar);
void onStopTrackingTouch(PieChartSeekBar pieChartSeekBar);
}
}
自定义属性颜色啥的自己来吧。。。。
使用
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/seat_set_background"
tools:context=".MainActivity">
<com.wuyazh.test.PieChartSeekBar
android:id="@+id/pie_chart_seek_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
```![扇形进度条.png](https://img.haomeiwen.com/i11008949/a3fee86894cb4717.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
网友评论