摘要 : 开启开篇一张图,内容全靠吹的模式(ctrl+c,ctrl+v)。
垂直Progress
ProgressBar 深入分析
ProgressBar 深入分析
通过上面吧垂直progress抽取出来。
修改进度条样式
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dip"/>
<gradient
android:angle="180"
android:centerColor="#ff5a5d5a"
android:centerY="0.75"
android:endColor="#ff747674"
android:startColor="#ff9d9e9d"
/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<corners android:radius="5dip"/>
<gradient
android:angle="180"
android:centerColor="#80ffb600"
android:centerY="0.75"
android:endColor="#a0ffcb00"
android:startColor="#80ffd300"
/>
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip
android:clipOrientation="vertical"
android:gravity="bottom">
<shape>
<corners android:radius="5dip"/>
<gradient
android:angle="180"
android:centerColor="#ffffb600"
android:centerY="0.75"
android:endColor="#ffffcb00"
android:startColor="#ffffd300"
/>
</shape>
</clip>
</item>
</layer-list>
android:clipOrientation:截取的方向。可取的值:horizontal和vertical。分别表 示水平和垂直方向截取图像。
android:gravity:表示如何截取图像。例如,left表示从左侧截取图像,right表示从右侧截取图像。
style
<style name="Progress_Vertical_Custom" parent="@android:style/Widget.ProgressBar.Horizontal">
<item name="android:progressDrawable">@drawable/progress_vertical</item>
<item name="android:indeterminateDrawable">
@android:drawable/progress_indeterminate_horizontal
</item>
<item name="android:minWidth">12dip</item>
<item name="android:maxWidth">12dip</item>
</style>
借助 NumberProgressBar实现
下载链接: NumberProgressBar
自定义属性
<declare-styleable name="NumberProgressBar">
<attr name="progress_current" format="integer"/>
<attr name="progress_max" format="integer"/>
<attr name="progress_unreached_color" format="color"/>
<attr name="progress_reached_color" format="color"/>
<attr name="progress_reached_bar_height" format="dimension"/>
<attr name="progress_unreached_bar_height" format="dimension"/>
<attr name="progress_text_size" format="dimension"/>
<attr name="progress_text_color" format="color"/>
<attr name="progress_text_offset" format="dimension"/>
<attr name="progress_text_visibility" format="enum">
<enum name="visible" value="0"/>
<enum name="invisible" value="1"/>
</attr>
</declare-styleable>
代码
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.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.sjjd.hu.office.R;
import com.sjjd.hu.utils.LogUtils;
import static com.sjjd.hu.widget.verticalpb.NumberProgressBar.ProgressTextVisibility.*;
/**
* =======================================
* 创建者 : 胡宇林
* 日 期 : 2018-03-22 - 17:54
* 描 述 :
* =======================================
*/
public class NumberProgressBar extends View {
private final String TAG = "NumberProgressBar->";
private int mMaxProgress = 100;
/**
* 当前进度,不能超过最大进度
*/
private int mCurrentProgress = 0;
/**
* 进度区域颜色
*/
private int mReachedBarColor;
/**
* 非进度区域颜色
*/
private int mUnreachedBarColor;
/**
* 进度文字颜色
*/
private int mTextColor;
/**
* 进度文字大小
*/
private float mTextSize;
/**
* 进度区域高度
*/
private float mReachedBarHeight;
/**
* 非进度区域高度
*/
private float mUnreachedBarHeight;
/**
* 文字显示的样式 perefix(前)、suffix(后)
*/
private String mPrefix = "";
private String mSuffix = "%";
private final int default_text_color = Color.rgb(66, 145, 241);
private final int default_reached_color = Color.rgb(66, 145, 241);
private final int default_unreached_color = Color.rgb(204, 204, 204);
private final float default_progress_text_offset;
private final float default_text_size;
private final float default_reached_bar_height;
private final float default_unreached_bar_height;
/**
* 对数据的保存与恢复
*/
private static final String INSTANCE_STATE = "saved_instance";
private static final String INSTANCE_TEXT_COLOR = "text_color";
private static final String INSTANCE_TEXT_SIZE = "text_size";
private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height";
private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color";
private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height";
private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color";
private static final String INSTANCE_MAX = "max";
private static final String INSTANCE_PROGRESS = "progress";
private static final String INSTANCE_SUFFIX = "suffix";
private static final String INSTANCE_PREFIX = "prefix";
private static final String INSTANCE_TEXT_VISIBILITY = "text_visibility";
private static final int PROGRESS_TEXT_VISIBLE = 0;
/**
* 文字的宽度
*/
private float mDrawTextWidth;
/**
* 文字的开始位置
*/
private float mDrawTextStart;
/**
* 文字的结束位置
*/
private float mDrawTextEnd;
/**
* 需要绘制的文字
*/
private String mCurrentDrawText;
/**
* 进度区域画笔
*/
private Paint mReachedBarPaint;
/**
* 非进度区域画笔
*/
private Paint mUnreachedBarPaint;
/**
* 画进度文字的画笔
*/
private Paint mTextPaint;
/**
* 非进度区域的矩形范围
*/
private RectF mUnreachedRectF = new RectF(0, 0, 0, 0);
/**
* 进度区域矩形
*/
private RectF mReachedRectF = new RectF(0, 0, 0, 0);
/**
* 进度文字偏移量
*/
private float mOffset;
/**
* 是否绘制未到的区域。
*/
private boolean mDrawUnreachedBar = true;
private boolean mDrawReachedBar = true;
private boolean mIfDrawText = true;
/**
* listener
*/
private OnProgressBarListener mListener;
public enum ProgressTextVisibility {
Visible, Invisible
}
//by add Yulin Hu 2018-03-23
//在宽比高大时为水平,如果高比宽大时为垂直
/**
* w > h = true
* h >= w = false ;
*/
private boolean maxWidthHeight = true;
private int viewWidth = 0;
private int viewHeight = 0;
private static final String MAX_WIDTH_HEIGHT = "max_width_height";
/**
* 文字的高度
*/
private float mDrawTextHeight;
/**
* 在实际使用中,普片都低于20%。显示效果很差,这里统一增加一个值(这里只针对有文字)
* 默认为有效高度的1/3
*/
private float raiseNum;
public NumberProgressBar(Context context) {
this(context, null, 0);
}
public NumberProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NumberProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
default_reached_bar_height = dp2px(1.5f);
default_unreached_bar_height = dp2px(1.0f);
default_text_size = sp2px(10);
default_progress_text_offset = dp2px(0.0f);
//初始化属性
final TypedArray attributes = context.getTheme().
obtainStyledAttributes(attrs, R.styleable.NumberProgressBar, defStyleAttr, 0);
mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color);
mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color, default_unreached_color);
mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color, default_text_color);
mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size);
mReachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_reached_bar_height, default_reached_bar_height);
mUnreachedBarHeight = attributes.getDimension(R.styleable.NumberProgressBar_progress_unreached_bar_height, default_unreached_bar_height);
mOffset = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_offset, default_progress_text_offset);
int textVisible = attributes.getInt(R.styleable.NumberProgressBar_progress_text_visibility, PROGRESS_TEXT_VISIBLE);
if (textVisible != PROGRESS_TEXT_VISIBLE) { //0 = visible
mIfDrawText = false;
}
setProgress(attributes.getInt(R.styleable.NumberProgressBar_progress_current, 0));
setMax(attributes.getInt(R.styleable.NumberProgressBar_progress_max, 100));
attributes.recycle();
initializePainters();
}
@Override
protected int getSuggestedMinimumWidth() {
return (int) mTextSize;
}
@Override
protected int getSuggestedMinimumHeight() {
return (int) Math.max(mTextSize, Math.max(mReachedBarHeight, mUnreachedBarHeight));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
viewWidth = measure(widthMeasureSpec, true);
viewHeight = measure(heightMeasureSpec, false);
if (viewWidth > viewHeight) {
maxWidthHeight = true;
} else {
maxWidthHeight = false;
raiseNum = (viewHeight - getPaddingTop() - getPaddingBottom()) / 1.50f;
}
LogUtils.i(TAG, "width = " + viewWidth + ",height = " + viewHeight + ",maxWH = " + maxWidthHeight);
setMeasuredDimension(viewWidth, viewHeight);
}
private int measure(int measureSpec, boolean isWidth) {
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
result += padding;
if (mode == MeasureSpec.AT_MOST) {
if (isWidth) {
result = Math.max(result, size);
} else { //高是反,余越靠近屏幕顶端越小
result = Math.min(result, size);
}
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
if (mIfDrawText) {
if (maxWidthHeight) {
calculateDrawRectF();
} else {
LogUtils.i(TAG, "calculateDrawRectFVertical()");
calculateDrawRectFVertical();
}
} else {
if (maxWidthHeight) {
calculateDrawRectFWithoutProgressText();
} else {
LogUtils.i(TAG, "calculateDrawRectFWithoutProgressTextVertical()");
calculateDrawRectFWithoutProgressTextVertical();
}
}
LogUtils.i(TAG, "mReachedRectF = " + mReachedRectF.toString());
LogUtils.i(TAG, "mUnreachedRectF = " + mUnreachedRectF.toString());
if (mDrawReachedBar) {
canvas.drawRect(mReachedRectF, mReachedBarPaint);
}
if (mDrawUnreachedBar) {
canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint);
}
if (mIfDrawText) {
canvas.drawText(mCurrentDrawText, mDrawTextStart, mDrawTextEnd, mTextPaint);
}
}
/**
* 初始化3支画笔
*/
private void initializePainters() {
mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mReachedBarPaint.setColor(mReachedBarColor);
mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mUnreachedBarPaint.setColor(mUnreachedBarColor);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
}
/**
* 进度绘制,不带文字
*/
private void calculateDrawRectFWithoutProgressText() {
mReachedRectF.left = getPaddingLeft();
mReachedRectF.top = (getHeight() / 2.0f) - (mReachedBarHeight / 2.0f);
mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) /
(getMax() * 1.0f) * getProgress() + getPaddingLeft();
mReachedRectF.bottom = (getHeight() / 2.0f) + (mReachedBarHeight / 2.0f);
mUnreachedRectF.left = mReachedRectF.right;
mUnreachedRectF.right = getWidth() - getPaddingRight();
mUnreachedRectF.top = getHeight() / 2.0f - mUnreachedBarHeight / 2.0f;
mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f;
}
/**
* 进度绘制,带文字
*/
private void calculateDrawRectF() {
mCurrentDrawText = String.format("%d", (getProgress() * 100) / getMax());
mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix;
mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
if (getProgress() == 0) { //暂无具体进度
mDrawReachedBar = false;
mDrawTextStart = getPaddingLeft();
} else {
mDrawReachedBar = true;
mReachedRectF.left = getPaddingLeft();
mReachedRectF.top = (getHeight() / 2.0f) - (mReachedBarHeight / 2.0f);
mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) /
(getMax() * 1.0f) * getProgress() - mOffset + getPaddingLeft();
mReachedRectF.bottom = (getHeight() / 2.0f) + (mReachedBarHeight / 2.0f);
mDrawTextStart = (mReachedRectF.right + mOffset);
}
mDrawTextEnd = (getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f);
if (mDrawTextStart + mDrawTextWidth >= getWidth() - getPaddingRight()) {
mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth;
mReachedRectF.right = mDrawTextStart - mOffset;
}
float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset;
if (unreachedBarStart > getWidth() - getPaddingRight()) {
mDrawUnreachedBar = false;
} else {
mDrawUnreachedBar = true;
mUnreachedRectF.left = unreachedBarStart;
mUnreachedRectF.right = getWidth() - getPaddingRight();
mUnreachedRectF.top = (getHeight() / 2.0f) - (mUnreachedBarHeight / 2.0f);
mUnreachedRectF.bottom = (getHeight() / 2.0f) + (mUnreachedBarHeight / 2.0f);
}
}
/**
* 进度文字颜色
*
* @return
*/
public int getTextColor() {
return mTextColor;
}
/**
* 进度文字大小
*
* @return
*/
public float getProgressTextSize() {
return mTextSize;
}
/**
* 进度区域颜色
*
* @return
*/
public int getUnreachedBarColor() {
return mUnreachedBarColor;
}
/**
* 非进度区域颜色
*
* @return
*/
public int getReachedBarColor() {
return mReachedBarColor;
}
/**
* 当前进度
*
* @return
*/
public int getProgress() {
return mCurrentProgress;
}
/**
* 最大进度
*
* @return
*/
public int getMax() {
return mMaxProgress;
}
/**
* 进度值
*
* @return
*/
public float getReachedBarHeight() {
return mReachedBarHeight;
}
/**
* 非进度值
*
* @return
*/
public float getUnreachedBarHeight() {
return mUnreachedBarHeight;
}
public void setProgressTextSize(float textSize) {
this.mTextSize = textSize;
mTextPaint.setTextSize(mTextSize);
invalidate();
}
public void setProgressTextColor(int textColor) {
this.mTextColor = textColor;
mTextPaint.setColor(mTextColor);
invalidate();
}
public void setUnreachedBarColor(int barColor) {
this.mUnreachedBarColor = barColor;
mUnreachedBarPaint.setColor(mUnreachedBarColor);
invalidate();
}
public void setReachedBarColor(int progressColor) {
this.mReachedBarColor = progressColor;
mReachedBarPaint.setColor(mReachedBarColor);
invalidate();
}
public void setReachedBarHeight(float height) {
mReachedBarHeight = height;
}
public void setUnreachedBarHeight(float height) {
mUnreachedBarHeight = height;
}
/**
* 设置最大值
*
* @param maxProgress
*/
public void setMax(int maxProgress) {
if (maxProgress > 0) {
this.mMaxProgress = maxProgress;
invalidate();
}
}
public void setSuffix(String suffix) {
if (suffix == null) {
mSuffix = "";
} else {
mSuffix = suffix;
}
}
public String getSuffix() {
return mSuffix;
}
public void setPrefix(String prefix) {
if (prefix == null)
mPrefix = "";
else {
mPrefix = prefix;
}
}
public String getPrefix() {
return mPrefix;
}
/**
* 持续增长
*
* @param by
*/
public void incrementProgressBy(int by) {
if (by > 0) {
setProgress(getProgress() + by);
}
if (mListener != null) {
mListener.onProgressChange(getProgress(), getMax());
}
}
/**
* 设置当前进度
*
* @param progress
*/
public void setProgress(int progress) {
if (progress <= getMax() && progress >= 0) {
this.mCurrentProgress = progress;
invalidate();
}
}
public void setEffectiveDate(int max, int progress, @ColorInt int reachedColor) {
if (max > 0) {
this.mMaxProgress = max;
}
if (progress <= getMax() && progress >= 0) {
this.mCurrentProgress = progress;
}
this.mReachedBarColor = reachedColor;
mReachedBarPaint.setColor(mReachedBarColor);
invalidate();
}
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
final Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
bundle.putInt(INSTANCE_TEXT_COLOR, getTextColor());
bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize());
bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT, getReachedBarHeight());
bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT, getUnreachedBarHeight());
bundle.putInt(INSTANCE_REACHED_BAR_COLOR, getReachedBarColor());
bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR, getUnreachedBarColor());
bundle.putInt(INSTANCE_MAX, getMax());
bundle.putInt(INSTANCE_PROGRESS, getProgress());
bundle.putString(INSTANCE_SUFFIX, getSuffix());
bundle.putString(INSTANCE_PREFIX, getPrefix());
bundle.putBoolean(INSTANCE_TEXT_VISIBILITY, getProgressTextVisibility());
bundle.putBoolean(MAX_WIDTH_HEIGHT, maxWidthHeight);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
final Bundle bundle = (Bundle) state;
mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR);
mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE);
mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT);
mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT);
mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR);
mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR);
initializePainters();
setMax(bundle.getInt(INSTANCE_MAX));
setProgress(bundle.getInt(INSTANCE_PROGRESS));
setPrefix(bundle.getString(INSTANCE_PREFIX));
setSuffix(bundle.getString(INSTANCE_SUFFIX));
setProgressTextVisibility(bundle.getBoolean(INSTANCE_TEXT_VISIBILITY) ? Visible : Invisible);
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
return;
}
super.onRestoreInstanceState(state);
}
public float dp2px(float dp) {
final float scale = getResources().getDisplayMetrics().density;
return dp * scale + 0.5f;
}
public float sp2px(float sp) {
final float scale = getResources().getDisplayMetrics().scaledDensity;
return sp * scale;
}
public void setProgressTextVisibility(ProgressTextVisibility visibility) {
mIfDrawText = visibility == Visible;
invalidate();
}
public boolean getProgressTextVisibility() {
return mIfDrawText;
}
public void setOnProgressBarListener(OnProgressBarListener listener) {
mListener = listener;
}
by add Yulin Hu
/**
* 进度绘制,不带文字
*/
private void calculateDrawRectFWithoutProgressTextVertical() {
mReachedRectF.left = getPaddingLeft();
mReachedRectF.top = getHeight() - ((getHeight() - getPaddingTop() - getPaddingBottom()) / (getMax() * 1.0f) * getProgress()) - getPaddingBottom();
mReachedRectF.right = getWidth() - getPaddingLeft() - getPaddingRight();
mReachedRectF.bottom = getHeight() - getPaddingBottom();
mUnreachedRectF.left = mReachedRectF.left;
mUnreachedRectF.top = getPaddingTop();
mUnreachedRectF.right = mReachedRectF.right;
mUnreachedRectF.bottom = mReachedRectF.top;
}
/**
* 进度绘制,带文字。这里把默认的自增也就算进去
*/
private void calculateDrawRectFVertical() {
mCurrentDrawText = String.format("%d", (getProgress() * 100) / getMax());
mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix;
mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mDrawTextHeight = metrics.bottom - metrics.top;
//设置不同默认增长,因为设定一个谷底你给的值后,后导致,没有什么差别了
float temp = getProgress() * 1.0f / getMax() * 1.0f;
LogUtils.i(TAG, "temp = " + temp);
if (temp < 0.05) {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 1;
} else if (temp < 0.1) {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 2;
} else if (temp < 0.15) {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 3;
} else if (temp < 0.2) {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 4;
} else if (temp < 0.25) {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 5;
} else {
raiseNum = (getHeight() - getPaddingTop() - getPaddingBottom()) / 8 * 6;
}
if (getProgress() == 0) { //暂无具体进度
mDrawReachedBar = false;
mReachedRectF.top = getHeight() - getPaddingBottom() - raiseNum;
mDrawTextEnd = getHeight() - getPaddingBottom() - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f) - raiseNum;
} else {
mDrawReachedBar = true;
mReachedRectF.left = getPaddingLeft();
//计算当前值因有的高度,这里需要减去默认raiseNum在计算
int tempProgressH = (int) ((getHeight() - getPaddingTop() - getPaddingBottom() - raiseNum) / (getMax() * 1.0f) * getProgress());
mReachedRectF.top = getHeight() - getPaddingBottom() - raiseNum - tempProgressH;//+ mDrawTextHeight + mOffset;
mReachedRectF.right = getWidth() - getPaddingLeft() - getPaddingRight();
mReachedRectF.bottom = getHeight() - getPaddingBottom();
mDrawTextEnd = mReachedRectF.top - mOffset - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f);
}
mDrawTextStart = ((getWidth() - getPaddingLeft() - getPaddingRight()) / 2.0f) - (mDrawTextWidth / 2.0f);
// mDrawTextHeight = mTextPaint.descent() - mTextPaint.ascent();
if (mReachedRectF.top - mOffset - mDrawTextHeight <= getPaddingTop()) {
mDrawTextEnd = getPaddingTop() + mDrawTextHeight + mOffset - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f);
mReachedRectF.top = mOffset + mDrawTextHeight + getPaddingTop();
}
float unreachedBarStart = mReachedRectF.top - mOffset - mDrawTextHeight;
if (unreachedBarStart <= getPaddingTop()) {
mDrawUnreachedBar = false;
} else {
mDrawUnreachedBar = true;
mUnreachedRectF.left = getPaddingLeft();
mUnreachedRectF.right = getWidth() - getPaddingRight();
mUnreachedRectF.top = getPaddingBottom();
mUnreachedRectF.bottom = unreachedBarStart;
}
LogUtils.i(TAG, "progress = " + getProgress());
LogUtils.i(TAG, "getHeight() : " + getHeight() + ",baseline : " + Math.abs(mTextPaint.descent() + mTextPaint.ascent()) + ",mDrawTextStart : " + mDrawTextStart + ",mDrawTextHeight : " + mDrawTextHeight);
LogUtils.i(TAG, ",mDrawTextStart = " + mDrawTextStart + ",mDrawTextEnd = " + mDrawTextEnd + ",mOffset = " + mOffset);
}
/*
*//**
* 进度绘制,带文字
*//*
private void calculateDrawRectFVertical() {
mCurrentDrawText = String.format("%d", (getProgress() * 100) / getMax());
mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix;
mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mDrawTextHeight = metrics.bottom - metrics.top;
if (getProgress() == 0) { //暂无具体进度
mDrawReachedBar = false;
mReachedRectF.top = getHeight() - getPaddingBottom();
mDrawTextEnd = getHeight() - getPaddingBottom() - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f);
} else {
mDrawReachedBar = true;
mReachedRectF.left = getPaddingLeft();
mReachedRectF.top = getHeight() - ((getHeight() - getPaddingTop() - getPaddingBottom()) / (getMax() * 1.0f) * (getProgress())) - getPaddingBottom();//+ mDrawTextHeight + mOffset;
mReachedRectF.right = getWidth() - getPaddingLeft() - getPaddingRight();
mReachedRectF.bottom = getHeight() - getPaddingBottom();
mDrawTextEnd = mReachedRectF.top - mOffset - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f);
}
mDrawTextStart = ((getWidth() - getPaddingLeft() - getPaddingRight()) / 2.0f) - (mDrawTextWidth / 2.0f);
// mDrawTextHeight = mTextPaint.descent() - mTextPaint.ascent();
if (mReachedRectF.top - mOffset - mDrawTextHeight <= getPaddingTop()) {
mDrawTextEnd = getPaddingTop() + mDrawTextHeight + mOffset - ((Math.abs(mTextPaint.descent() + mTextPaint.ascent())) / 2.0f);
mReachedRectF.top = mOffset + mDrawTextHeight + getPaddingTop();
}
float unreachedBarStart = mReachedRectF.top - mOffset - mDrawTextHeight;
if (unreachedBarStart <= getPaddingTop()) {
mDrawUnreachedBar = false;
} else {
mDrawUnreachedBar = true;
mUnreachedRectF.left = getPaddingLeft();
mUnreachedRectF.right = getWidth() - getPaddingRight();
mUnreachedRectF.top = getPaddingBottom();
mUnreachedRectF.bottom = unreachedBarStart;
}
LogUtils.i(TAG, "progress = " + getProgress());
LogUtils.i(TAG, "getHeight() : " + getHeight() + ",baseline : " + Math.abs(mTextPaint.descent() + mTextPaint.ascent()) + ",mDrawTextStart : " + mDrawTextStart + ",mDrawTextHeight : " + mDrawTextHeight);
LogUtils.i(TAG, ",mDrawTextStart = " + mDrawTextStart + ",mDrawTextEnd = " + mDrawTextEnd + ",mOffset = " + mOffset);
}*/
}
监听器
public interface OnProgressBarListener {
void onProgressChange(int current, int max);
}
百分比圆盘
代码
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.sjjd.hu.utils.LogUtils;
/**
* =======================================
* 创建者 : 胡宇林
* 日 期 : 2018-03-26 - 16:36
* 描 述 :
* =======================================
*/
public class PieChart extends View {
private final String TAG = "PieChart->";
private final int DEFAULT_SIZE = 146;
private final int DEFAULT_OUTSIDE_CIRCULAR_RADIUS = 50;
private final int DEFAULT_OUTSIDE_CIRCULAR_COLOR = Color.parseColor("#1C1F21");
/**
* 目前只有两块区域,一个为实体值、一个为剩下进度
*/
private int DEFAULT_VALUE_COLOR = Color.parseColor("#E72C2D");
private int DEFAULT_UNVALUE_COLOR = Color.parseColor("#FFFFFF");
private Paint mPiePaint;
/**
* 外圈有一个阴影颜色
*/
private Paint mOutsideCircluarPaint;
private int mOutsideCircylarRadius; //半径
private int mOutsideCircylarX; //x
private int mOutsideCircylarY; //y
private int mOutsideCircularColor;
/**
* 这里为一半的尺寸,圆有左右两个部分
*/
private int mOutsideCircularSize = 26;
private int mValueColor;
private int mUnValueColor;
private float mValue = 60;
private float total = 100;
/**
* 角度
*/
private RectF mValueRectF;
/**
* 对数据的保存与恢复
*/
private static final String INSTANCE_STATE = "saved_instance";
private static final String OUTSIDE_CIRCULAR_SIZE = "outside_circular_size";
private static final String OUTSIDE_CIRCULAR_COLOR = "outside_circular_color";
private static final String VALUE_TOTATL = "value_totatl";
private static final String VALUE_VALUE = "valute_value";
private static final String VALUE_VALUE_COLOR = "value_value_color";
private static final String VALUE_UNVALUE_COLOR = "value_unvalue_color";
public PieChart(Context context) {
this(context, null, 0);
}
public PieChart(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PieChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mOutsideCircularColor = DEFAULT_OUTSIDE_CIRCULAR_COLOR;
mValueColor = DEFAULT_VALUE_COLOR;
mUnValueColor = DEFAULT_UNVALUE_COLOR;
mOutsideCircylarRadius = DEFAULT_OUTSIDE_CIRCULAR_RADIUS;
initializePainters();
}
@Override
protected int getSuggestedMinimumWidth() {
return DEFAULT_SIZE;
}
@Override
protected int getSuggestedMinimumHeight() {
return DEFAULT_SIZE;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = measure(widthMeasureSpec, true);
int h = measure(heightMeasureSpec, false);
int size = Math.min(w, h);
mOutsideCircylarRadius = (int) (size / 2.0f);
mOutsideCircylarX = (int) ((w - getPaddingLeft() - getPaddingRight()) / 2.0f);
mOutsideCircylarY = (int) ((h - getPaddingTop() - getPaddingBottom()) / 2.0f);
mValueRectF = new RectF();
mValueRectF.left = mOutsideCircylarX - mOutsideCircylarRadius + mOutsideCircularSize;
mValueRectF.top = mOutsideCircylarY - mOutsideCircylarRadius + mOutsideCircularSize;
mValueRectF.right = mOutsideCircylarX + mOutsideCircylarX - mOutsideCircularSize;
mValueRectF.bottom = mOutsideCircylarY + mOutsideCircylarRadius - mOutsideCircularSize;
LogUtils.i(TAG, "w = " + w + ",h = " + h + ",PaddingLeft() = " + getPaddingLeft() + ",PaddingRight() = " + getPaddingRight());
LogUtils.i(TAG, "size = " + size + ",x = " + mOutsideCircylarX + ",y = " + mOutsideCircylarY + ",radius = " + mOutsideCircylarRadius);
setMeasuredDimension(size, size);
}
private int measure(int measurespec, boolean isWidth) {
int result;
int mode = MeasureSpec.getMode(measurespec);
int size = MeasureSpec.getSize(measurespec);
int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
result += padding;
if (mode == MeasureSpec.AT_MOST) {
if (isWidth) {
// result = Math.max(result, size);
//这里也取最小值,因为在wrap情况下宽度为最大值
result = Math.min(result, size);
} else {
result = Math.min(result, size);
}
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
LogUtils.i(TAG, "paint color = " + Integer.toHexString(mOutsideCircularColor));
LogUtils.i(TAG, "x = " + mOutsideCircylarX + ",y = " + mOutsideCircylarY + ",radius = " + mOutsideCircylarRadius);
canvas.drawCircle(mOutsideCircylarX, mOutsideCircylarY, mOutsideCircylarRadius, mOutsideCircluarPaint);
//默认只有两个区域
float sweepAngle = (360 / total) * mValue;
float temp = 360.f - sweepAngle;
if (temp < 0) {
temp = 0;
}
LogUtils.i(TAG, "sweepAngle = " + sweepAngle + ",temp = " + temp + ",calc = " + (360 / total));
mPiePaint.setColor(mUnValueColor);
canvas.drawArc(mValueRectF, -90, temp, true, mPiePaint);
mPiePaint.setColor(mValueColor);
canvas.drawArc(mValueRectF, temp - 90, sweepAngle, true, mPiePaint);
}
private void initializePainters() {
mPiePaint = new Paint();
mPiePaint.setAntiAlias(true);
mOutsideCircluarPaint = new Paint();
mOutsideCircluarPaint.setAntiAlias(true);
mOutsideCircluarPaint.setColor(mOutsideCircularColor);
mOutsideCircluarPaint.setStrokeWidth(5);
}
public int getOutsideCircularColor() {
return mOutsideCircularColor;
}
/**
* 外框的颜色
*
* @param outsideCircularColor
*/
public void setOutsideCircularColor(@ColorInt int outsideCircularColor) {
mOutsideCircularColor = outsideCircularColor;
}
public int getValueColor() {
return mValueColor;
}
/**
* 具体值得颜色
*
* @param valueColor
*/
public void setValueColor(int valueColor) {
mValueColor = valueColor;
}
public int getUnValueColor() {
return mUnValueColor;
}
/**
* 设置具非具体指的圆盘颜色
*
* @param unValueColor
*/
public void setUnValueColor(int unValueColor) {
mUnValueColor = unValueColor;
}
public float getValue() {
return mValue;
}
/**
* 有效数
*
* @param value
*/
public void setValue(float value) {
if (value >= 0)
mValue = value;
invalidate();
}
public float getTotal() {
return total;
}
/**
* 比例的总数
*
* @param total
*/
public void setTotal(float total) {
if (total > 0)
this.total = total;
invalidate();
}
public int getOutsideCircularSize() {
return mOutsideCircularSize;
}
public void setOutsideCircularSize(int outsideCircularSize) {
if (outsideCircularSize >= 0) {
mValueRectF.left = mOutsideCircylarX - mOutsideCircylarRadius + mOutsideCircularSize;
mValueRectF.top = mOutsideCircylarY - mOutsideCircylarRadius + mOutsideCircularSize;
mValueRectF.right = mOutsideCircylarX + mOutsideCircylarX - mOutsideCircularSize;
mValueRectF.bottom = mOutsideCircylarY + mOutsideCircylarRadius - mOutsideCircularSize;
mOutsideCircularSize = outsideCircularSize;
}
}
public void setEffectiveDate(float total, float value, @ColorInt int valueColor) {
if (total > 0) {
this.total = total;
}
if (value >= 0) {
this.mValue = value;
}
this.mValueColor = valueColor;
invalidate();
}
public void setEffectiveDate(float total, float value, String valueColor) {
if (total > 0) {
this.total = total;
}
if (value >= 0) {
this.mValue = value;
}
this.mValueColor = Color.parseColor(valueColor);
invalidate();
}
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
bundle.putInt(OUTSIDE_CIRCULAR_SIZE, getOutsideCircularSize());
bundle.putInt(OUTSIDE_CIRCULAR_COLOR, getOutsideCircularColor());
bundle.putFloat(VALUE_TOTATL, getTotal());
bundle.putFloat(VALUE_VALUE, getValue());
bundle.putInt(VALUE_VALUE_COLOR, getValueColor());
bundle.putInt(VALUE_UNVALUE_COLOR, getUnValueColor());
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mOutsideCircularSize = bundle.getInt(OUTSIDE_CIRCULAR_SIZE);
mOutsideCircularColor = bundle.getInt(OUTSIDE_CIRCULAR_COLOR);
total = bundle.getFloat(VALUE_TOTATL);
mValue = bundle.getFloat(VALUE_VALUE);
mValueColor = bundle.getInt(VALUE_VALUE_COLOR);
mUnValueColor = bundle.getInt(VALUE_UNVALUE_COLOR);
setOutsideCircularSize(mOutsideCircularSize);
setOutsideCircularColor(mOutsideCircularColor);
setTotal(total);
setValue(mValue);
setValueColor(mValueColor);
setUnValueColor(mUnValueColor);
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
}
super.onRestoreInstanceState(state);
}
}