Android自定义View实现很简单
继承View,重写构造函数、onDraw,(onMeasure)等函数。
如果自定义的View需要有自定义的属性,需要在values下建立attrs.xml。在其中定义你的属性。
在使用到自定义View的xml布局文件中需要加入xmlns:前缀=”http://schemas.android.com/apk/res/你的自定义View所在的包路径”.
1、制作简易手表
先写一个类继承View,重写onMeasure(),onDraw()
public class MyView extends View {
private int width;
private int height;
private Paint mPaintDuan;
private Paint mPaintLine;
private Paint mPaintSecond;
private Paint mPaintCircle;
private Paint mPaintText;
private Calendar mCalendar;
public static final int NEED_INVALIDATE=0X23;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case NEED_INVALIDATE:
mCalendar = Calendar.getInstance();//每次要刷新时间
invalidate();//告诉主线程重新绘制
handler.sendEmptyMessageDelayed(NEED_INVALIDATE, 1000);
break;
}
}
};
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mCalendar =Calendar.getInstance();
mPaintDuan = new Paint();//设置直线的参数
mPaintDuan.setColor(Color.RED);
mPaintDuan.setStrokeWidth(8);
mPaintLine = new Paint();//设置直线的参数
mPaintLine.setColor(Color.GREEN);
mPaintLine.setStrokeWidth(10);
mPaintSecond= new Paint();//设置秒针线的参数
mPaintSecond.setColor(Color.GREEN);
mPaintSecond.setStrokeWidth(5);
mPaintCircle = new Paint();//设置圆的参数
mPaintCircle.setColor(Color.LTGRAY);
mPaintCircle.setStrokeWidth(10);
mPaintCircle.setStyle(Paint.Style.STROKE);
mPaintText = new Paint();
mPaintText.setColor(Color.BLACK);
mPaintText.setTextSize(30);
mPaintText.setTextAlign(Paint.Align.CENTER);
handler.sendEmptyMessage(NEED_INVALIDATE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//是由UI主线程自动调用,只需要在此绘制即可
// canvas.drawLine(0,0,300,300,mPaintLine);//画直线
// canvas.drawCircle(350,350,100,mPaintCircle);//画圆
canvas.drawCircle(width / 2, height / 2, 300, mPaintCircle);
canvas.drawCircle(width / 2, height / 2, 10, mPaintCircle);
for (int i = 1; i <= 12; i++) {//用FOR循环画12条短线
canvas.save();//保存画布当前的状态
canvas.rotate(360 / 12 * i, width / 2, height / 2);//旋转画布,每次转30度
canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 280, mPaintDuan);
canvas.drawText("" + i, width / 2, height / 2 - 250, mPaintText);
canvas.restore();
}
//获得分钟数,小时数
int minute = mCalendar.get(Calendar.MINUTE);
int hour = mCalendar.get(Calendar.HOUR);
float minuteDegree = minute / 60f * 360;//获得分针的旋转度
canvas.save();
canvas.rotate(minuteDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2, width / 2, height / 2 - 200, mPaintLine);
canvas.restore();
float hourDegree = (hour*60+minute)/12f/60*360;//计算时针所占表盘的度数
canvas.save();
canvas.rotate(hourDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2, width / 2, height / 2 - 150, mPaintLine);
canvas.restore();
int second = mCalendar.get(Calendar.SECOND);
float secondDegree = second/60f*360;//计算秒针此刻的位置
canvas.save();
canvas.rotate(secondDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2, width / 2, height / 2 - 230, mPaintSecond);
canvas.restore();
}
}
然后再布局文件下添加这个view
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.my.administrator.zdyview.MyView//这里的MyView要和上面写的类名一致
android:id="@+id/tiaoxingview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
在Activity中只需要 setContentView(R.layout.activity_main);即可。
简易手表如下:
2、往容器中倒满水案例
public class TiaoxingView extends View {
private int width;
private int height;
private Paint lineLeft;
private Paint lineRight;
private Paint lineButtom;
private Paint lineNewRight;
private Paint mPaintText;
private int progress=100;
private int progressCurrent;
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
public int getProgressCurrent() {
return progressCurrent;
}
public void setProgressCurrent(int progressCurrent) {
this.progressCurrent = progressCurrent;
invalidate();//告诉主线程重新绘制
}
public TiaoxingView(Context context) {
super(context);
}
public TiaoxingView(Context context, AttributeSet attrs) {
super(context, attrs);
lineLeft=new Paint();
lineLeft.setColor(Color.BLACK);
lineLeft.setStrokeWidth(5);
lineRight=new Paint();
lineRight.setColor(Color.BLACK);
lineRight.setStrokeWidth(5);
lineButtom=new Paint();
lineButtom.setColor(Color.BLACK);
lineButtom.setStrokeWidth(5);
lineNewRight=new Paint();
lineNewRight.setColor(Color.GREEN);
lineNewRight.setStrokeWidth(300);
mPaintText = new Paint();
mPaintText.setColor(Color.BLUE);
mPaintText.setTextSize(60);
mPaintText.setTextAlign(Paint.Align.CENTER);//设置文本在给定坐标中间
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制如下图的容器
canvas.drawLine(50, 100, 50, 500, lineLeft);
canvas.drawLine(50,500,350,500,lineButtom);
canvas.drawLine(350,500,350,100,lineRight);
canvas.drawLine(200,500,200,500-progressCurrent*400f/progress,lineNewRight);//progressCurrent*400f/progress是此时应该画的长度,progressCurrent从activity中获得
canvas.drawText(progressCurrent*100f/progress+"%",200,300,mPaintText);//给定文本坐标,写入文本
}
}
布局问价:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始" />
<com.my.administrator.zdyview.TiaoxingView
android:id="@+id/tiaoxingview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Activity
public class MainActivity extends AppCompatActivity {
private TiaoxingView view;
private Button mButton;
private int progress;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0x21:
progress++;
if (progress <= 100) {
view.setProgressCurrent(progress);//设置当前的进度
handler.sendEmptyMessageDelayed(0x21, 200);
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (TiaoxingView) findViewById(R.id.tiaoxingview);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.sendEmptyMessage(0x21);
}
});
}
}
运行如下:
弧形进度条案例
其他代码和上面相同,view类如下:
public class ArcView extends View {
private int width;
private int height;
private int progress=100;
private int progressCurrent;
private Paint mCircle;
private Paint mArc;
private RectF mRectf;
private Paint mText;
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
public int getProgressCurrent() {
return progressCurrent;
}
public void setProgressCurrent(int progressCurrent) {
this.progressCurrent = progressCurrent;
invalidate();
}
public ArcView(Context context) {
super(context);
}
public ArcView(Context context, AttributeSet attrs) {
super(context, attrs);
mArc = new Paint();
mArc.setColor(Color.GREEN);
mArc.setStrokeWidth(50);
mArc.setStyle(Paint.Style.STROKE);
mCircle = new Paint();
mCircle.setColor(Color.GRAY);
mCircle.setStyle(Paint.Style.STROKE);
mCircle.setStrokeWidth(10);
mText = new Paint();
mText.setColor(Color.BLUE);
mText.setTextSize(60);
mText.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(width / 2, height / 2, 300, mCircle);
canvas.drawCircle(width / 2, height / 2, 250, mCircle);
mRectf = new RectF(width/2-275,height/2-275,width/2+275,height/2+275);//设置画弧度的矩形框
canvas.drawArc(mRectf,0,progressCurrent*360f/progress,false,mArc);
canvas.drawText(progressCurrent * 100f / progress + "%", width / 2, height / 2, mText);
}
}
运行如下;