如何自定义控件
1: 自定义属性的声明与获取,建attrs文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="HorizontalProgressbarWithProgress">
<attr name="progress_unreach_color" format="color" />
<attr name="progress_unreach_height" format="dimension" />
<attr name="progress_reach_color" format="color" />
<attr name="progress_reach_height" format="dimension" />
<attr name="progress_text_color" format="color" />
<attr name="progress_text_size" format="dimension" />
<attr name="progress_text_offset" format="dimension" />
</declare-styleable>
</resources>
在main-java-包下边建立HorizontalProgressbarWithProgress.java文件
并继承ProgressBar,重写方法
public class HorizontalProgressbarWithProgress extends ProgressBar{
}
通过getContext().obtainStyledAttributes获取自定义属性,存放至TypedArray
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);
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);
mTextOffset=(int)ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_text_offset,mTextOffset);
ta.recycle();
2: 测量onMeasure
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int widthVal=MeasureSpec.getSize(widthMeasureSpec);
int height=measureHeitht(heightMeasureSpec);//获取高度(分情况)
setMeasuredDimension(widthVal,height);//确定view的宽和高
mRealWidth=getMeasuredWidth()-getPaddingLeft()-getPaddingRight();
}
private int measureHeitht(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());//获得文字的高度
//getPaddingBottom()+getPaddingTop()是必须要加的,之后测量reach,UNreach和文字的最大值
result=getPaddingBottom()+getPaddingTop()+
Math.max(Math.max(mReachHeight,mUnReachHeight),Math.abs(textHeight));
if(mode==MeasureSpec.AT_MOST){//该模式,测量的值不能超过给定的size
result=Math.min(result,size);
}
}
return result ;
}
3: 绘制onDraw
@Override
protected synchronized void onDraw(Canvas canvas) {
boolean noNeedUnReach=false;//不显示
//注:canvas.save();和canvas.restore();是两个相互匹配出现,操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态
canvas.save();//保存画布的状态
canvas.translate(getPaddingLeft(),getHeight()/2);//将坐标移动到左边中间
//draw reach
float radio=getProgress()*1.0f/getMax();//得到绘制长度占总长度百分比
String text=getProgress()+"%";
int textWidth=(int)mPaint.measureText(text);//测量文字的宽度
float progressX=radio*mRealWidth;
if(progressX+textWidth>mRealWidth){//如果reach和文字的长度的和大于总长度
progressX=mRealWidth-textWidth;
noNeedUnReach=true;
}
float endX=radio*mRealWidth-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
if(!noNeedUnReach){//为true,显示
float start=progressX+mTextOffset/2+textWidth;
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mUnReachHeight);
canvas.drawLine(start,0,mRealWidth,0,mPaint);
}
canvas.restore();//取出保存的状态
}
到此,自定义控件设计完成
在MainActivity.java
public class MainActivity extends Activity {
private HorizontalProgressbarWithProgress mHProgress;
private static 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);
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHProgress=(HorizontalProgressbarWithProgress)findViewById(R.id.id_progress01);
mHandler.sendEmptyMessage(MSG_UPDATE);
}
}
在xml中布局
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:hyman="http://schemas.android.com/apk/res-auto"
tools:context="com.example.administrator.progressbartest.MainActivity"
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.administrator.progressbartest.HorizontalProgressbarWithProgress
android:id="@+id/id_progress01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:progress="0"
hyman:progress_unreach_color="#ff000000"
android:padding="15dp"
hyman:progress_reach_color="@color/colorAccent"
android:layout_marginTop="30dp"
/>
<com.example.administrator.progressbartest.HorizontalProgressbarWithProgress
android:id="@+id/id_progress02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
hyman:progress_reach_color="#99ffff00"
android:progress="20"
android:padding="5dp"
hyman:progress_unreach_color="#77ffff00"
android:layout_marginTop="60dp"
/>
</LinearLayout>
</ScrollView>