1 说明
据说现在很多人都开始使用Android Studio,我也开始用用吧,现在还在慢慢摸索中。。。。今天在慕课上学啦制作进度条,现在就来总结一下吧。
对了Android Studio的单词大写快捷键: Ctrl + Shift + U ;
2 效果图
3 实现步骤总结
1 建一个继承ProgressBar的类
这里暂时只需要把构造方法添加进去即可(一个参数,两个参数的和三个参数的)。
2 创建资源文件
这里主要是定义自己的控件的属性名称。如图:
3 到继承了ProgressBar的类中实现onMeasure和OnDraw
onMeasure(int widthMeasureSpec, int heightMeasureSpec):对尺寸进行测量;
onDraw(Canvas canvas):绘制图形;
以上两个方法只需要复写就可以了,View中会自动调用的。
4 具体代码
4.1 首先values中创建 atts.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>
<!-- 这里是类名 HorizontalProgressBarView -->
<declare-styleable name="HorizontalProgressBarView">
<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>
4.2 其次就是HorizontalProgressBarView类
package com.example.hyf.appforprogress.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ProgressBar;
import com.example.hyf.appforprogress.R;
/**
* Created by Administrator on 2016/5/18.
*/
public class HorizontalProgressBarView extends ProgressBar {
private String Tag = "houyafei" ;
//定义默认值
private static final int DEFAULT_TEXT_SIZE = 10 ; // sp
private static final int DEFAULT_TEXT_COLOR = 0xFFFc00d1 ;
private static final int DEFAULT_UNREACH_COLOR = 0xffd3d6da ;
private static final int DEFAULT_UNREACH_HEIGHT = 2 ; // dp
private static final int DEFAULT_REACH_COLOR = DEFAULT_TEXT_COLOR ;
private static final int DEFAULT_REACH_HEIGHT= 3 ; // dp
private static final int DEFAULT_TEXT_OFFSET = 10 ; // dp
//使用默认值
private float mTextSize = (float)sp2px(DEFAULT_TEXT_SIZE) ;
private int mTextColor = DEFAULT_TEXT_COLOR ;
private int mUnreachColor = DEFAULT_UNREACH_COLOR;
private int mUnreachHeight = dp2px(DEFAULT_UNREACH_HEIGHT);
private int mReachColor = DEFAULT_REACH_COLOR ;
private int mReachHeight = dp2px(DEFAULT_REACH_HEIGHT);
private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET) ;
private Paint mPaint = new Paint();
private int mRealWidth ;
public HorizontalProgressBarView(Context context) {
this(context,null);
}
public HorizontalProgressBarView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public HorizontalProgressBarView(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.HorizontalProgressBarView);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//注意,这里的属性名称前都加了类名和下划线,与atts.xml文件中的名称做下对比
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
mTextSize = ta.getDimension(R.styleable.HorizontalProgressBarView_progress_text_size,
mTextSize);
mTextColor = ta.getColor(R.styleable.HorizontalProgressBarView_progress_text_color,
mTextColor) ;
mUnreachColor = ta.getColor(R.styleable.HorizontalProgressBarView_progress_unreach_color,
mUnreachColor);
mUnreachHeight = (int) ta.getDimension(R.styleable.HorizontalProgressBarView_progress_unreach_height,
mUnreachHeight);
mReachColor = ta.getColor(R.styleable.HorizontalProgressBarView_progress_reach_color,
mReachColor);
mReachHeight = (int) ta.getDimension(R.styleable.HorizontalProgressBarView_progress_reach_height,
mReachHeight);
mTextOffset = (int) ta.getDimension(R.styleable.HorizontalProgressBarView_progress_text_offset,
mTextOffset);
ta.recycle();
//设置字体大小 ,用于后面计算控件的高度
mPaint.setTextSize(mTextSize);
}
/**
*
* @param dpVal
* @return
*/
private int dp2px(int dpVal){
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal,getResources().getDisplayMetrics());
}
/**
*
* @param spVal
* @return
*/
private int sp2px(int spVal){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal,getResources().getDisplayMetrics());
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取宽度的模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
//获取宽度的值,通过宽度的模式来获取 宽度的值
int widthVal = MeasureSpec.getSize(widthMeasureSpec);
//获取控件高度的值
int height = getHeightMeasure(heightMeasureSpec);
//设置控件的尺寸
setMeasuredDimension(widthVal,height);
//设置控件的实际宽度
mRealWidth = getMeasuredWidth()-getPaddingLeft()-getPaddingRight();
}
/**
*
* @param heightMeasureSpec
* @return
*/
private int getHeightMeasure(int heightMeasureSpec) {
int result = 0 ;
//获得测量模式
int mode = MeasureSpec.getMode(heightMeasureSpec);
//获取测量结果--高度
int size = MeasureSpec.getSize(heightMeasureSpec);
//用户的提供的是精确的数值模式
if(mode==MeasureSpec.EXACTLY){
result = size ;
}else{
//下部分的之减去上部分的值
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
//
result = getPaddingTop()+getPaddingBottom()+
Math.max(Math.abs(textHeight),Math.max(mReachHeight,mUnreachHeight));
if(mode==MeasureSpec.AT_MOST){
result = Math.min(result,size);
}
}
return result ;
}
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
//绘制其实坐标
canvas.translate(getPaddingLeft(),getHeight()/2);
// 代表是否需要绘制onReachbar
boolean isNeedUnReach = false ;
float radio = getProgress()*1.0f/getMax() ;
//测量文本宽度
String text = getProgress()+"%" ;
int textWidth = (int) mPaint.measureText(text);
//
float progressX = radio*mRealWidth ;
//保证数字被显示
if(progressX+textWidth>mRealWidth){
progressX = mRealWidth - textWidth ;
isNeedUnReach = true ;
}
//绘制进度条的进度长度
float endX = progressX - mTextOffset/2 ;
if(endX>0){
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
canvas.drawLine(0,0,endX, 0, mPaint);
}
//绘制文本
mPaint.setColor(mTextColor);
mPaint.setAntiAlias(true);
int y = (int) (-(mPaint.descent()+mPaint.ascent())/2);
canvas.drawText(text,progressX,y,mPaint);
//绘制unReachbar
if (!isNeedUnReach){
float start = progressX + mTextOffset/2 + textWidth ;
mPaint.setColor(mUnreachColor);
mPaint.setStrokeWidth(mUnreachHeight);
canvas.drawLine(start,0,mRealWidth,0,mPaint);
}
canvas.restore();
}
}
4.3 在布局文件中引用自定义的进度条
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="20dp">
<com.example.hyf.appforprogress.views.HorizontalProgressBarView
android:id="@+id/id_pro_01"
android:layout_width="match_parent"
android:layout_height="50dp"
android:progress="43"
android:max="100"
app:progress_unreach_height="2dp"
app:progress_text_size="13sp"
app:progress_reach_color="#ff009900"
app:progress_unreach_color="#66009900"
app:progress_text_color="#2caf2c"
/>
</LinearLayout>
5 测量模式
/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/**
* Measure specification mode: The parent has determined an exact size
* for the child. The child is going to be given those bounds regardless
* of how big it wants to be.
*/
public static final int EXACTLY = 1 << MODE_SHIFT;
/**
* Measure specification mode: The child can be as large as it wants up
* to the specified size.
*/
public static final int AT_MOST = 2 << MODE_SHIFT;
MeasureSpec.UNSPECIFIED :
是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
MeasureSpec.EXACTLY:
精确的测量模式
MeasureSpec.AT_MOST:
是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
6 还有圆形可以设置
参考我的第二篇文章:
自定义环形进度显示之
《(Android Studio)自定义 ProgressBar(二)》