您的位置:首页 > 其它

打造炫酷进度条

2016-05-30 10:55 260 查看
如何自定义控件

1.自定义属性的声明与获取

2.测量onMeasure

3.布局onLayout(ViewGroup)

4.绘制onDraw

5.onTouchEvent

6.onInterceptTouchEvent(ViewGroup)

7.状态的恢复与保存

自定义属性的声明与获取

1.分析需要的自定义属性

2.在res/values/attrs.xml定义声明

3.在layout文件中进行使用

4.在View的构造方法中进行获取

条形进度条

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<attr name="progress_unreach_color" format="color"></attr>
<attr name="progress_unreach_height" format="dimension"></attr>
<attr name="progress_reach_color" format="color"></attr>
<attr name="progress_reach_height" format="dimension"></attr>
<attr name="progress_text_color" format="color"></attr>
<attr name="progress_text_size" format="dimension"></attr>
<attr name="progress_text_offset" format="dimension"></attr>

<declare-styleable name="HorizontalProgressBarWithProgress">

<attr name="progress_unreach_color"></attr>
<attr name="progress_unreach_height"></attr>
<attr name="progress_reach_color"></attr>
<attr name="progress_reach_height"></attr>
<attr name="progress_text_color"></attr>
<attr name="progress_text_size"></attr>
<attr name="progress_text_offset"></attr>

</declare-styleable>

</resources>

HorizontalProgressBarWithProgress.java

public class HorizontalProgressBarWithProgress extends ProgressBar {

private static final int DEFAULT_TEXT_SIZE = 10; // sp
private static final int DEFAULT_TEXT_COLOR = 0xFFFC00D1;
private static final int DEFAULT_COLOR_UNREACH = 0xFFD3D6DA;
private static final int DEFAULT_HEIGHT_UNREACH = 2; // dp
private static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOR;
private static final int DEFAULT_HEIGHT_REACH = 2; // dp
private static final int DEFAULT_TEXT_OFFSET = 10; // dp

private int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
private int mTextColor = DEFAULT_TEXT_COLOR;
private int mUnReachColor = DEFAULT_COLOR_UNREACH;
private int mUnReachHeight = dp2px(DEFAULT_HEIGHT_UNREACH);
private int mReachColor = DEFAULT_COLOR_REACH;
private int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH);
private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);

private Paint mPaint = new Paint();

/**
* 在onMeasure中初始化
* 在onDraw中使用
*/
private int mRealWidth;

public HorizontalProgressBarWithProgress(Context context) {
this(context, null);
}

public HorizontalProgressBarWithProgress(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public HorizontalProgressBarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

//获取自定义属性
obtainStyledAttrs(attrs);
}

/**
* 获取自定义属性
*
* @param attrs
*/
private void obtainStyledAttrs(AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs,
R.styleable.HorizontalProgressBarWithProgress);

mTextSize = (int) ta.getDimension(
R.styleable.HorizontalProgressBarWithProgress_progress_text_size, mTextSize);

mTextColor = ta.getColor(
R.styleable.HorizontalProgressBarWithProgress_progress_text_color, mTextColor);

mTextOffset = (int) ta.getDimension(
R.styleable.HorizontalProgressBarWithProgress_progress_text_offset, mTextOffset);

mUnReachColor = ta.getColor(
R.styleable.HorizontalProgressBarWithProgress_progress_unreach_color, mUnReachColor);

mUnReachHeight = (int) ta.getDimension(
R.styleable.HorizontalProgressBarWithProgress_progress_unreach_height, mUnReachHeight);

mReachColor = ta.getColor(
R.styleable.HorizontalProgressBarWithProgress_progress_reach_color, mReachColor);

mReachHeight = (int) ta.getDimension(
R.styleable.HorizontalProgressBarWithProgress_progress_reach_height, mReachHeight);

ta.recycle();

mPaint.setTextSize(mTextSize);
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthVal = MeasureSpec.getSize(widthMeasureSpec);

int height = measureHeight(heightMeasureSpec);

//确定view的宽和高
setMeasuredDimension(widthVal, height);

mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
}

private int measureHeight(int heightMeasureSpec) {

int result = 0;
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);

//精确值(如match_parent、200dp一类)
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
//当前绘制底线(descent) 当前绘制顶线(ascent) ascent为负值
//结果为文字的高度
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
result = getPaddingTop() + getPaddingBottom() +
Math.max(Math.max(mReachHeight, mUnReachHeight), Math.abs(textHeight));

//测量值不能超过给定的size值
if (mode == MeasureSpec.AT_MOST) {
return Math.min(result, size);
}

}

return result;

}

@Override
protected synchronized void onDraw(Canvas canvas) {
canvas.save();

canvas.translate(getPaddingLeft(), getHeight() / 2);

boolean noNeedUnReach = false;

//draw reach bar
String text = getProgress() + "%";

int textWidth = (int) mPaint.measureText(text);

float radio = getProgress() * 1.0f / getMax();

float progressX = radio * mRealWidth;

if (progressX + textWidth > mRealWidth) {
progressX = mRealWidth - textWidth;
noNeedUnReach = true;
}

float endX = progressX - mTextOffset / 2;

if (endX > 0) {
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}

//draw text
mPaint.setColor(mTextColor);
int y = (int) (-(mPaint.descent() + mPaint.ascent()) / 2);
canvas.drawText(text, progressX, y, mPaint);

//draw unreach bar
if (!noNeedUnReach) {
float start = progressX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mUnReachHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}

canvas.restore();
}

private int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
getResources().getDisplayMetrics());
}

private int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
getResources().getDisplayMetrics());
}

}

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:liu="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<com.example.view.HorizontalProgressBarWithProgress
android:id="@+id/id_progress01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="15dp"
android:progress="0"
liu:progress_reach_color="#ffff0000"
liu:progress_text_color="#ffff0000"
liu:progress_unreach_color="#44ff0000" />

<com.example.view.HorizontalProgressBarWithProgress
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="15dp"
android:progress="100"
liu:progress_text_color="#44ff0000"
liu:progress_unreach_color="#ffff0000" />

<com.example.view.HorizontalProgressBarWithProgress
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="15dp"
android:progress="30"
liu:progress_text_color="#44ff0000"
liu:progress_unreach_color="#ffff0000" />

</LinearLayout>
</ScrollView>

MainActivity.java

public class MainActivity extends AppCompatActivity {

private final int MSG_UPDATE = 0x110;

private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int progress = mHProgress.getProgress();
mHProgress.setProgress(++progress);
if (progress >= 100) {
mHandler.removeMessages(MSG_UPDATE);
}
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, 100);
}
};

private HorizontalProgressBarWithProgress mHProgress;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHProgress = (HorizontalProgressBarWithProgress) findViewById(R.id.id_progress01);

mHandler.sendEmptyMessage(MSG_UPDATE);
}
}


圆形进度条

attrs.xml

<declare-styleable name="RoundProgressBarWithProgress">

<attr name="radius" format="dimension"></attr>

</declare-styleable>

activity_main.xml
<com.example.view.RoundProgressBarWithProgress
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="15dp"
android:progress="30"
liu:radius="20dp"
liu:progress_text_color="#ff000000"
liu:progress_unreach_color="#ffff0000" />

<com.example.view.RoundProgressBarWithProgress
android:id="@+id/id_progress02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:padding="15dp"
android:progress="0"
liu:radius="60dp"
liu:progress_text_color="#ff000000"
liu:progress_text_size="30sp"
liu:progress_unreach_color="#44ff0000" />

RoundProgressBarWithProgress.java

public class RoundProgressBarWithProgress extends HorizontalProgressBarWithProgress {

private int mRadius = dp2px(30);

private int mMaxPaintWidth;

public RoundProgressBarWithProgress(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public RoundProgressBarWithProgress(Context context) {
this(context, null);
}

public RoundProgressBarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

mReachHeight = (int) (mUnReachHeight * 2.5f);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBarWithProgress);
mRadius = (int) ta.getDimension(R.styleable.RoundProgressBarWithProgress_radius, mRadius);

ta.recycle();

//设置画笔为空心
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//防抖动
mPaint.setDither(true);
//设置画笔的笔触风格
//ROUND 圆角的笔触
mPaint.setStrokeCap(Paint.Cap.ROUND);
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxPaintWidth = Math.max(mReachHeight, mUnReachHeight);
//默认四个padding一致
int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight();

int width = resolveSize(expect, widthMeasureSpec);
int height = resolveSize(expect, heightMeasureSpec);

int realWidth = Math.min(width, height);

mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2;

setMeasuredDimension(realWidth, realWidth);

}

@Override
protected synchronized void onDraw(Canvas canvas) {
String text = getProgress() + "%";
float textWidth = mPaint.measureText(text);
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

canvas.save();

canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop() + mMaxPaintWidth / 2);
mPaint.setStyle(Paint.Style.STROKE);

//draw unreach bar
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mUnReachHeight);
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);

//draw reach bar
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
//弧度
float sweepAngle = getProgress() * 1.0f / getMax() * 360;
canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0, sweepAngle, false, mPaint);

//draw text
mPaint.setColor(mTextColor);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint);

canvas.restore();
}
}

https://github.com/LiuchangDuan/demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: