android自定义进度条样式,Android 自定义进度条
效果
國際慣例,效果圖奉上
在這里插入圖片描述
目錄
在這里插入圖片描述
前言
寫在前面,由于之前其實已經寫了部分自定義View的方法,所以本來應該按照之前的系列,來進行下載暫停動畫進度條,但是我把之前的圓形進度條和開始暫停動畫效果合并后,出現了一點小問題,讓我發現之前寫的自定義View,沒有使我真正的了解自定義View,那么我覺得還是有很大的問題;那么之后依舊會努力的寫自定義View,初步先寫靜態的自定義View,之后,加上動畫的自定義VIew,后續在加上相應的觸摸事件,努力的把自定義VIew的方法方式全部給記錄下來;努力的融匯貫通。
正文
HorizontalProgressBarWithNumber
橫向的進度條;里面有詳細的注釋
首先繼承自ProgressBar,這個是對基礎的ProgressBar 進行進一步的自定義,
public class HorizontalProgressBarWithNumber extends ProgressBar{
******
}
當我們想要自定義VIew的時候,先要構思效果,那么就要設置各種屬性,如下
/**
* 設置各種默認值
*/
private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/**
* painter of all drawing things 所有畫圖所用的畫筆
*/
protected Paint mPaint = new Paint();
/**
* color of progress number 進度號碼的顏色
*/
protected int mTextColor = DEFAULT_TEXT_COLOR;
/**
* size of text (sp) 文本的大小
*/
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/**
* offset of draw progress 進度條文本補償寬度
*/
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar 進度條高度
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar 成功的文本顏色
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar 未完成的bar顏色
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar 未覆蓋的進度條高度
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding 除padding外的視圖寬度
*/
protected int mRealWidth;
protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0;
自定義構造函數
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
obtainStyledAttributes(attrs);//初始化參數
mPaint.setTextSize(mTextSize);//文本大小
mPaint.setColor(mTextColor);//文本顏色
}
接下來就是初始化的代碼:
/**
* get the styled attributes 獲取屬性的樣式
*
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs)
{
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
mTextSize);
mReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
mTextOffset);
int textVisible = attributes
.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE)
{
mIfDrawText = false;
}
attributes.recycle();
}
上面當中的參數和屬性都在attr.xml中聲明的,如下
接下來,我們要重寫onMeasure方法,在其中獲取父控件傳遞過來的參數
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);//高度
setMeasuredDimension(width, height);//必須調用該方法來存儲View經過測量的到的寬度和高度
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的寬度值是減去左右padding
}
其中measureHeight() 方法是獲取視圖的高度,視圖的樣式中擁有進度條和文本,要判斷文本的高度和進度條的高度;
/**
* EXACTLY:父控件告訴我們子控件了一個確定的大小,你就按這個大小來布局。比如我們指定了確定的dp值和macth_parent的情況。
* AT_MOST:當前控件不能超過一個固定的最大值,一般是wrap_content的情況。
* UNSPECIFIED:當前控件沒有限制,要多大就有多大,這種情況很少出現。
* @param measureSpec
* @return 視圖的高度
*/
private int measureHeight(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);//父布局告訴我們控件的類型
int specSize = MeasureSpec.getSize(measureSpec);//父布局傳過來的視圖大小
if (specMode == MeasureSpec.EXACTLY)
{
result = specSize;
} else
{
/**
* mPaint.descent() 最高點的高度
* mPaint.ascent() 最低點的高度
*/
float textHeight = (mPaint.descent() - mPaint.ascent());// 設置文本的高度
/**
* Math.abs() 返回絕對值
* Math.max 返回最大值
* Math.min 返回最小值
*/
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));
if (specMode == MeasureSpec.AT_MOST)
{
result = Math.min(result, specSize);
}
}
return result;
}
以上全部完成后,就可以開始onDraw()方法了;
/**
* 開始畫
*/
@Override
protected synchronized void onDraw(Canvas canvas)
{
canvas.save();
/**
* 設置偏移后的坐標原點 以原來為基礎上偏移后, 例如: (100,100), translate(1,1), 坐標原點(101,101);
*/
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false;
float radio = getProgress() * 1.0f / getMax();//設置進度
float progressPosX = (int) (mRealWidth * radio);//設置當前進度的寬度
String text = getProgress() + "%";//設置文本
// mPaint.getTextBounds(text, 0, text.length(), mTextBound);
float textWidth = mPaint.measureText(text);//返回文本的寬度
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;//設置文本的高度
if (progressPosX + textWidth > mRealWidth)
{//當文本和當前進度的寬度大于bar的寬度時
progressPosX = mRealWidth - textWidth;
noNeedBg = true;
}
// draw reached bar 畫出bar
float endX = progressPosX - mTextOffset / 2;//繪制已到達的進度
if (endX > 0)
{//繪制已到達的進度
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// draw progress bar
// measure text bound
if (mIfDrawText)
{//繪制文本
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// draw unreached bar
if (!noNeedBg)
{//繪制未到達的進度條
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
在分享兩個轉換的方法
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
/**
* sp 2 px
*
* @param spVal
* @return
*/
protected int sp2px(int spVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
最后自定義View 全部實現,奉上全部代碼
public class HorizontalProgressBarWithNumber extends ProgressBar
{
/**
* 設置各種默認值
*/
private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/**
* painter of all drawing things 所有畫圖所用的畫筆
*/
protected Paint mPaint = new Paint();
/**
* color of progress number 進度號碼的顏色
*/
protected int mTextColor = DEFAULT_TEXT_COLOR;
/**
* size of text (sp) 文本的大小
*/
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/**
* offset of draw progress 進度條文本補償寬度
*/
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar 進度條高度
*/
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar 成功的文本顏色
*/
protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/**
* color of unreached bar 未完成的bar顏色
*/
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/**
* height of unreached progress bar 未覆蓋的進度條高度
*/
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding 除padding外的視圖寬度
*/
protected int mRealWidth;
protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0;
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
obtainStyledAttributes(attrs);//初始化參數
mPaint.setTextSize(mTextSize);//文本大小
mPaint.setColor(mTextColor);//文本顏色
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);//高度
setMeasuredDimension(width, height);//必須調用該方法來存儲View經過測量的到的寬度和高度
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();//真正的寬度值是減去左右padding
}
/**
* EXACTLY:父控件告訴我們子控件了一個確定的大小,你就按這個大小來布局。比如我們指定了確定的dp值和macth_parent的情況。
* AT_MOST:當前控件不能超過一個固定的最大值,一般是wrap_content的情況。
* UNSPECIFIED:當前控件沒有限制,要多大就有多大,這種情況很少出現。
* @param measureSpec
* @return 視圖的高度
*/
private int measureHeight(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);//父布局告訴我們控件的類型
int specSize = MeasureSpec.getSize(measureSpec);//父布局傳過來的視圖大小
if (specMode == MeasureSpec.EXACTLY)
{
result = specSize;
} else
{
/**
* mPaint.descent() 最高點的高度
* mPaint.ascent() 最低點的高度
*/
float textHeight = (mPaint.descent() - mPaint.ascent());// 設置文本的高度
/**
* Math.abs() 返回絕對值
* Math.max 返回最大值
* Math.min 返回最小值
*/
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight,
mUnReachedProgressBarHeight), Math.abs(textHeight)));
if (specMode == MeasureSpec.AT_MOST)
{
result = Math.min(result, specSize);
}
}
return result;
}
/**
* get the styled attributes 獲取屬性的樣式
*
* @param attrs
*/
private void obtainStyledAttributes(AttributeSet attrs)
{
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(
attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size,
mTextSize);
mReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor = attributes
.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes
.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,
mTextOffset);
int textVisible = attributes
.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE)
{
mIfDrawText = false;
}
attributes.recycle();
}
/**
* 開始畫
*/
@Override
protected synchronized void onDraw(Canvas canvas)
{
canvas.save();
/**
* 設置偏移后的坐標原點 以原來為基礎上偏移后, 例如: (100,100), translate(1,1), 坐標原點(101,101);
*/
canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false;
float radio = getProgress() * 1.0f / getMax();//設置進度
float progressPosX = (int) (mRealWidth * radio);//設置當前進度的寬度
String text = getProgress() + "%";//設置文本
// mPaint.getTextBounds(text, 0, text.length(), mTextBound);
float textWidth = mPaint.measureText(text);//返回文本的寬度
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;//設置文本的高度
if (progressPosX + textWidth > mRealWidth)
{//當文本和當前進度的寬度大于bar的寬度時
progressPosX = mRealWidth - textWidth;
noNeedBg = true;
}
// draw reached bar 畫出bar
float endX = progressPosX - mTextOffset / 2;//設置文本補償寬度
if (endX > 0)
{
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// draw progress bar
// measure text bound
if (mIfDrawText)
{
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// draw unreached bar
if (!noNeedBg)
{
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
}
/**
* dp 2 px
*
* @param dpVal
*/
protected int dp2px(int dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
/**
* sp 2 px
*
* @param spVal
* @return
*/
protected int sp2px(int spVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRealWidth = w - getPaddingRight() - getPaddingLeft();
}
}
實現
xml界面
xmlns:tools="http://schemas.android.com/tools"
xmlns:zhy="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
android:id="@+id/id_progressbar01"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="50dip"
android:padding="5dp" />
mainActivity() 實現
public class MainActivity extends Activity {
private HorizontalProgressBarWithNumber mProgressBar;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int progress = mProgressBar.getProgress();
mProgressBar.setProgress(++progress);
if (progress >= 100) {
mHandler.removeMessages(MSG_PROGRESS_UPDATE);
}
mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE, 100);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = (HorizontalProgressBarWithNumber) findViewById(R.id.id_progressbar01);
mHandler.sendEmptyMessage(MSG_PROGRESS_UPDATE);
}
以上就是全部功能的實現了
總結
自定義View
先構思效果
根據效果 , 聲明配置相應參數
想好怎么計算View的寬度和高度
如果畫出來
開始做吧
感謝
這個是從鴻陽大神的Github上找到的例子,嗯,值得學習,感謝鴻陽大神;
總結
以上是生活随笔為你收集整理的android自定义进度条样式,Android 自定义进度条的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年电工中级电工证(四级)理论知识
- 下一篇: 空间转录组整合方法SPOTlight