package com.xscm.moduleutil.widget; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import com.xscm.moduleutil.R; public class PKProgressBar extends View { // 文字背景颜色 private int textBgColor = 0; // 绘制跟随进度条移动的数字的画笔 private Paint paintNumber; private Paint bitmapPaint; private Paint paintBar; private Paint paintOtherBar; private Paint paintLight; private Paint leftTextPaintBg; private Paint rightTextPaintBg; private int backGroundColor = Color.GRAY; private int barColor = Color.RED; private Drawable leftDrawable; private Drawable rightDrawable; private Drawable rightDrawableOne; private Drawable rightDrawableTwo; private Drawable rightDrawableThree; private OnProgressChangeListener onProgressChangeListener; private int halfDrawableWidth = 0; private int halfDrawableHeight = 0; private int barPadding = 0; private boolean isRound = true; private float progress = 50f; private float max = 100f; private double progressPercentage = 0.5; private float viewWidth = 0f; private int viewHeight = 0; private int progressWidth = 100; private RectF rectFBG = new RectF(); private RectF rectFPB = new RectF(); private RectF rectFPBO = new RectF(); private Path barRoundPath = new Path(); private Path barRoundPathOther = new Path(); private Rect rectLeftText = new Rect(); private Rect rectRightText = new Rect(); private Rect rectLeftFollowText = new Rect(); private Rect rectRightFollowText = new Rect(); private Paint paintRightText; private Paint paintLeftText; private Paint paintBackGround; // 是否使用颜色渐变器 private boolean isGradient = false; // 颜色渐变器 private LinearGradient linearGradient; private LinearGradient linearGradientOther; private int gradientStartColor = Color.RED; private int gradientEndColor = Color.YELLOW; private int otherGradientStartColor = Color.RED; private int otherGradientEndColor = Color.YELLOW; private int barStartWidth = 0; // 进度条最大绘制位置与最小绘制位置 private int barEndWidth = 0; // 圆角大小 private float barRadioSize = 0f; private int textColor = Color.WHITE; private int textSize = 12; private boolean textIsBold = true; // 蓝方 private String leftTextStr = ""; // 红方 private String rightTextStr = ""; private String leftTeamName = ""; private String leftTeamCount = ""; private String rightTeamName = ""; private String rightTeamCount = ""; private String leftFollowTextStr = ""; private String rightFollowTextStr = ""; private Bitmap lightBitmap; private int lightDrawableId = 0; private float leftTextStrWidth = 0f; private float leftTextStrHeight = 0f; private float leftTextStrMargin = 21; private float commonMargin = 6; private float leftTextStrBg = 57; private float rightTextStrWidth = 0f; private float rightTextStrHeight = 0f; private float rightTextStrMargin = 21; private float leftFollowWidth = 0f; private float leftFollowHeight = 0f; private float rightFollowWidth = 0f; private float rightFollowHeight = 0f; private float followMargin = 16; /** * 左侧队名显示状态 */ private boolean leftTeamNameVisible = true; /** * 左侧团队人数的显示状态 */ private boolean leftTeamCountVisible = true; /** * 右侧队名显示状态 */ private boolean rightTeamNameVisible = true; /** * 右侧团队人数的显示状态 */ private boolean rightTeamCountVisible = true; /** * 左侧的队名宽度 */ private float leftTeamNameWidth = 0f; /** * 左侧的团队人数宽度 */ private float leftTeamCountWidth = 0f; /** * 右侧的队名的宽度 */ private float rightTeamNameWidth = 0f; /** * 右侧的团队人数宽度 */ private float rightTeamCountWidth = 0f; /** * 右侧用户头像边距 */ private final float rightAvatarMargin = 10; /** * 右侧用户头像宽度 */ private final float rightAvatarwidth = 58; public PKProgressBar(Context context) { super(context); init(); } public PKProgressBar(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PKProgressBar_pk, 0, 0); backGroundColor = typedArray.getColor(R.styleable.PKProgressBar_pk_backGroundColor, Color.GRAY); barColor = typedArray.getColor(R.styleable.PKProgressBar_pk_barColor, Color.RED); leftDrawable = typedArray.getDrawable(R.styleable.PKProgressBar_pk_leftDrawableBg); rightDrawable = typedArray.getDrawable(R.styleable.PKProgressBar_pk_rightDrawableBg); halfDrawableWidth = typedArray.getDimensionPixelSize(R.styleable.PKProgressBar_pk_halfDrawableWidth, 1); halfDrawableHeight = typedArray.getDimensionPixelSize(R.styleable.PKProgressBar_pk_halfDrawableHeight, 1); barPadding = typedArray.getDimensionPixelSize(R.styleable.PKProgressBar_pk_barPadding, 0); isRound = typedArray.getBoolean(R.styleable.PKProgressBar_pk_isRound, true); max = typedArray.getInt(R.styleable.PKProgressBar_pk_max, 100); lightDrawableId = typedArray.getResourceId(R.styleable.PKProgressBar_pk_lightDrawable, 0); textColor = typedArray.getColor(R.styleable.PKProgressBar_pk_textColor, Color.BLACK); textSize = typedArray.getDimensionPixelSize(R.styleable.PKProgressBar_pk_textSize, 13); textIsBold = typedArray.getBoolean(R.styleable.PKProgressBar_pk_textIsBold, false); isGradient = typedArray.getBoolean(R.styleable.PKProgressBar_pk_isGradient, false); gradientStartColor = typedArray.getColor(R.styleable.PKProgressBar_pk_gradientStartColor, Color.RED); gradientEndColor = typedArray.getColor(R.styleable.PKProgressBar_pk_gradientEndColor, Color.YELLOW); otherGradientStartColor = typedArray.getColor(R.styleable.PKProgressBar_pk_otherGradientStartColor, Color.RED); otherGradientEndColor = typedArray.getColor(R.styleable.PKProgressBar_pk_otherGradientEndColor, Color.YELLOW); typedArray.recycle(); init(); } public PKProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 底部边框背景 paintBackGround = new Paint(); paintBackGround.setColor(backGroundColor); paintBackGround.setAntiAlias(true); paintLight = new Paint(); paintLight.setAntiAlias(true); // 左半部分进度条 paintBar = new Paint(); paintBar.setColor(barColor); paintBar.setAntiAlias(true); // 右半部分进度条 paintOtherBar = new Paint(); paintOtherBar.setColor(barColor); paintOtherBar.setAntiAlias(true); // 左半部分文字 // Typeface plain = Typeface.createFromAsset(getContext().getAssets(), "Roboto-BlackItalic.ttf");/**/ paintLeftText = new Paint(); // paintLeftText.setTypeface(plain); paintLeftText.setStyle(Paint.Style.FILL); paintLeftText.setColor(textColor); paintLeftText.setTextSize(textSize); leftTextStrWidth = paintLeftText != null ? paintLeftText.measureText(leftTextStr) : 0; leftTextStrHeight = paintLeftText != null ? paintLeftText.descent() - paintLeftText.ascent() : 0; // 团队数字 // Typeface plainNumber = Typeface.createFromAsset(getContext().getAssets(), "Roboto-BlackItalic.ttf"); paintNumber = new Paint(); // paintNumber.setTypeface(plainNumber); paintNumber.setStyle(Paint.Style.FILL); paintNumber.setColor(textColor); paintNumber.setTextSize(24); // 左半部文字的背景 leftTextPaintBg = new Paint(); leftTextPaintBg.setStyle(Paint.Style.FILL); leftTextPaintBg.setColor(textBgColor); leftTextPaintBg.setAntiAlias(true); // 右半部分文字 paintRightText = new Paint(); paintRightText.setStyle(Paint.Style.FILL); paintRightText.setColor(textColor); paintRightText.setTextSize(textSize); paintRightText.setFakeBoldText(textIsBold); paintRightText.setAntiAlias(true); paintRightText.setTextSkewX(-0.25f); if (lightDrawableId != 0) { lightBitmap = BitmapFactory.decodeResource(getResources(), lightDrawableId); } getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(this); // 是否需要渐变器 if (isGradient) { linearGradient = new LinearGradient( 0f, viewHeight / 2f, progressWidth, viewHeight / 2f, gradientStartColor, gradientEndColor, Shader.TileMode.CLAMP ); linearGradientOther = new LinearGradient( 0f, viewHeight / 2f, progressWidth, viewHeight / 2f, otherGradientStartColor, otherGradientEndColor, Shader.TileMode.CLAMP ); if (paintBar != null) { paintBar.setShader(linearGradient); } if (paintOtherBar != null) { paintOtherBar.setShader(linearGradientOther); } } return false; } }); } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); // 光标水平位置 viewWidth = ((progressWidth - 3 * barPadding) * (float) progressPercentage + barPadding); viewWidth = Math.max(viewWidth, leftTextStrBg + leftTextStrMargin + leftFollowWidth); viewWidth = Math.min( viewWidth, progressWidth - commonMargin - barPadding - rightAvatarMargin - rightAvatarwidth - rightFollowWidth - followMargin ); viewHeight = getHeight(); // 圆角大小,为实际进度条高度一半 if (isRound) { barRadioSize = (viewHeight - barPadding * 2) / 2f; } // 绘制底部边框 drawBackground(canvas); // 绘制左半部分进度条 drawLeftBar(canvas); // 绘制右半部分进度条 drawRightBar(canvas); // 绘制透明图层 drawPicture(canvas); // 绘制横向半透明光柱 drawLight(canvas); // 绘制跟随进度条移动的文字 drawFollowText(canvas); // 绘制队伍信息 drawTeamInfoText(canvas); } private void drawFollowText(Canvas canvas) { float leftFollowStart = getBoundaryPosition() - leftFollowWidth - halfDrawableWidth - followMargin; float rightFollowStart = getBoundaryPosition() + rightFollowWidth + halfDrawableWidth + followMargin; leftTeamCountVisible = leftFollowStart > leftTextStrBg + leftTeamNameWidth + leftTextStrMargin * 2 + leftTeamCountWidth; leftTeamNameVisible = leftFollowStart > leftTextStrBg + commonMargin + leftTeamNameWidth; rightTeamCountVisible = rightFollowStart < (progressWidth - commonMargin * 2 - barPadding - rightAvatarMargin - rightAvatarwidth - rightTeamNameWidth - rightTeamCountWidth); rightTeamNameVisible = rightFollowStart < (progressWidth - commonMargin - rightTeamNameWidth - barPadding - rightAvatarMargin - rightAvatarwidth); } private void drawLight(Canvas canvas) { if (lightBitmap == null) { return; } canvas.save(); // 将画布坐标系移动到画布中央 canvas.translate(0f, barPadding); Rect src = new Rect(barStartWidth, 0, barEndWidth, (viewHeight - barPadding) / 2); canvas.drawBitmap(lightBitmap, src, src, paintLight); canvas.restore(); } private void drawBackground(Canvas canvas) { canvas.save(); rectFBG.set(0f, 0f, progressWidth, viewHeight); if (isRound) { Path path = new Path(); path.addRoundRect(new RectF(0f, 0f, getMeasuredWidth(), getMeasuredHeight()), viewHeight / 2f, viewHeight / 2f, Path.Direction.CW); // 先对canvas进行裁剪 canvas.clipPath(path, Region.Op.INTERSECT); } else { if (paintBackGround != null) { canvas.drawRect(rectFBG, paintBackGround); } } canvas.restore(); } private void drawLeftBar(Canvas canvas) { float right = getBoundaryPosition(); float[] radios = { barRadioSize, barRadioSize, 0f, 0f, 0f, 0f, barRadioSize, barRadioSize }; canvas.save(); rectFPB.set(barPadding, barPadding, right - halfDrawableWidth, viewHeight - barPadding); barRoundPath.reset(); barRoundPath.addRoundRect(rectFPB, radios, Path.Direction.CCW); barRoundPath.close(); if (isRound) { if (paintBar != null) { canvas.drawPath(barRoundPath, paintBar); } } else { if (paintBar != null) { canvas.drawRect(rectFPB, paintBar); } } canvas.restore(); } private void drawRightBar(Canvas canvas) { float left = getBoundaryPosition(); float[] radios = { 0f, 0f, barRadioSize, barRadioSize, barRadioSize, barRadioSize, 0f, 0f }; canvas.save(); rectFPBO.set(left + halfDrawableWidth, barPadding, barEndWidth, viewHeight - barPadding); barRoundPathOther.reset(); barRoundPathOther.addRoundRect(rectFPBO, radios, Path.Direction.CCW); barRoundPathOther.close(); if (isRound) { if (paintOtherBar != null) { canvas.drawPath(barRoundPathOther, paintOtherBar); } } else { if (paintOtherBar != null) { canvas.drawRect(rectFPBO, paintOtherBar); } } canvas.restore(); } private void drawTeamInfoText(Canvas canvas) { // 左侧 // 绘制文字的背景 if (leftTextPaintBg != null) { leftTextPaintBg.setColor(textBgColor); canvas.drawRoundRect(13, 13, 57, viewHeight - 13, viewHeight / 2f, viewHeight / 2f, leftTextPaintBg); } if (paintLeftText != null) { canvas.drawText(leftTextStr, leftTextStrMargin, viewHeight / 2f + leftTextStrHeight / 3f, paintLeftText); } if (leftTeamNameVisible && paintLeftText != null) { // 队名 canvas.drawText(leftTeamName, leftTextStrBg + commonMargin, viewHeight / 2f + leftTextStrHeight / 3f, paintLeftText); } if (leftTeamCountVisible && paintLeftText != null) { // 队伍人数 // canvas.drawText(leftTeamCount, leftTextStrBg + leftTeamNameWidth + commonMargin * 2, viewHeight / 2f + leftTextStrHeight / 3f, paintLeftText); } // 右侧 if (rightTeamNameVisible && paintRightText != null) { // 右侧队名 canvas.drawText(rightTeamName, progressWidth - commonMargin - rightTeamNameWidth - barPadding - rightAvatarMargin - rightAvatarwidth, viewHeight / 2f + leftTextStrHeight / 3f, paintRightText); } if (rightTeamCountVisible && paintRightText != null) { // 右侧团队人数 // canvas.drawText(rightTeamCount, progressWidth - commonMargin * 2 - barPadding - rightAvatarMargin - rightAvatarwidth - rightTeamNameWidth - rightTeamCountWidth, viewHeight / 2f + leftTextStrHeight / 3f, paintRightText); } } /** * 获取极限位置进度条的绘制位置 * 1. 最左边 * 2. 最左边到圆角区段位置 * 3. 中间正常位置 * 4. 最右边圆角区段位置 * 5. 最右边 * * @return 极限位置进度条的绘制位置 */ private float getBoundaryPosition() { // 默认为计算的比例位置 float boundaryPos = viewWidth; if (progressPercentage == 0.0 || viewWidth == barStartWidth) { // 光标位于最左边 boundaryPos = barPadding + leftTextStrBg + leftTextStrMargin + leftFollowWidth; } else if (progressPercentage == 1.0 || viewWidth == barEndWidth) { // 光标位于最右边 boundaryPos = barEndWidth - rightAvatarwidth - rightAvatarMargin; } else if ((viewWidth - barStartWidth < barRadioSize || viewWidth - barStartWidth == barRadioSize) && viewWidth > barStartWidth) { boundaryPos = Math.max(viewWidth, barRadioSize + barStartWidth); } else if ((viewWidth > barEndWidth - barRadioSize || viewWidth == barEndWidth - barRadioSize) && viewWidth < barEndWidth) { // 光标位于进度条右侧弧形区域 boundaryPos = Math.min(viewWidth, barEndWidth - barRadioSize); } return boundaryPos; } private void drawPicture(Canvas canvas) { if (leftDrawable != null) { leftDrawable.setBounds(0, 0, 180, viewHeight); leftDrawable.draw(canvas); } if (rightDrawable != null) { rightDrawable.setBounds( (int) rectFPBO.right - 180, (int) rectFPBO.top, (int) rectFPBO.right, (int) rectFPBO.bottom ); rightDrawable.draw(canvas); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { width = halfDrawableWidth * 2; } if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) { height = halfDrawableHeight * 2; } // 记录进度条总长度 progressWidth = width; // 记录进度条起始位置 barStartWidth = barPadding; // 记录进度条结束位置 barEndWidth = progressWidth - barPadding; setMeasuredDimension(width, height); leftTextStrWidth = paintRightText != null ? paintRightText.measureText(leftTextStr) : 0; leftTextStrHeight = paintLeftText != null ? paintLeftText.descent() - paintLeftText.ascent() : 0; rightTextStrWidth = paintRightText != null ? paintRightText.measureText(rightTextStr) : 0; rightTextStrHeight = paintRightText != null ? paintRightText.descent() - paintRightText.ascent() : 0; leftFollowWidth = paintNumber != null ? paintNumber.measureText(leftFollowTextStr) : 0; leftFollowHeight = paintNumber != null ? paintNumber.descent() - paintNumber.ascent() : 0; rightFollowWidth = paintNumber != null ? paintNumber.measureText(rightFollowTextStr) : 0; rightFollowHeight = paintNumber != null ? paintNumber.descent() - paintNumber.ascent() : 0; rightTeamNameWidth = paintLeftText != null ? paintLeftText.measureText(rightTeamName) : 0; rightTeamCountWidth = paintLeftText != null ? paintLeftText.measureText(rightTeamCount) : 0; leftTeamNameWidth = paintLeftText != null ? paintLeftText.measureText(leftTeamName) : 0; leftTeamCountWidth = paintLeftText != null ? paintLeftText.measureText(leftTeamCount) : 0; } /** * 进度变化监听器接口 */ public interface OnProgressChangeListener { /** * 当进度发生变化时触发 * * @param progress 当前进度值 */ void onOnProgressChange(int progress); /** * 当进度完成时触发 */ void onOnProgressFinish(); } /** * 根据左右值设置动画进度 * * @param leftValue 左值 * @param rightValue 右值 */ public synchronized void setAnimProgress(long leftValue, long rightValue) { leftFollowTextStr = String.valueOf(leftValue); rightFollowTextStr = String.valueOf(rightValue); if (leftValue + rightValue == 0L) { setAnimProgress(50f); } else { setAnimProgress(100f * leftValue / (leftValue + rightValue)); } } /** * 传入百分比值设置动画进度 * * @param progressValue 百分比值 */ public void setAnimProgress(float progressValue) { if (progressValue < 0 || progressValue > 100) { return; } ValueAnimator animator = ValueAnimator.ofFloat(progress, progressValue); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { setProgress(Float.parseFloat(valueAnimator.getAnimatedValue().toString())); } }); Interpolator interpolator = new AccelerateDecelerateInterpolator(); animator.setInterpolator(interpolator); animator.setDuration((long) (Math.abs(progress - progressValue) * 20)); animator.start(); } public void setProgress(float progressValue) { if (progress <= max) { progress = progressValue; } else if (progress < 0) { progress = 0f; } else { progress = max; } progressPercentage = progress / max; doProgressRefresh(); invalidate(); } private synchronized void doProgressRefresh() { if (onProgressChangeListener != null) { onProgressChangeListener.onOnProgressChange((int) progress); if (progress >= max) { onProgressChangeListener.onOnProgressFinish(); } } } // 设置颜色渐变器 public void setLinearGradient(LinearGradient linearGradient) { this.linearGradient = linearGradient; } // 设置进度监听器 public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) { this.onProgressChangeListener = onProgressChangeListener; } }