您的位置:首页 > 移动开发 > Android开发

Android自定义控件——时钟、进度条

2015-09-17 09:23 441 查看
由于Android提供的空间有限,不能满足程序的需求,所以才有了自定义控件

时钟

首先要写一个类继承自View

package com.example.administrator.myselfview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import java.util.Calendar;

/**
* Created by Administrator on 2015/9/16.
*/
public class MyAlarmview extends View {
private int width;
private int height;
private Paint mPaintLine;
private Paint mPaintSecondLine;
private Paint mPaintCricle;
private Paint mPaintText;
private Calendar mCalendar;
public static final int UPDATE_TIME=0X22;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case UPDATE_TIME:
mCalendar=Calendar.getInstance();
invalidate();
handler.sendEmptyMessageDelayed(UPDATE_TIME,1000);
break;
}
}
};
public MyAlarmview(Context context) {
super(context);
}

public MyAlarmview(Context context, AttributeSet attrs) {
super(context, attrs);
mPaintLine=new Paint();
mPaintLine.setColor(Color.BLACK);//设置颜色
mPaintLine.setStrokeWidth(10);//画笔宽度

mPaintSecondLine=new Paint();
mPaintSecondLine.setColor(Color.GRAY);
mPaintSecondLine.setStrokeWidth(5);

mPaintCricle=new Paint();
mPaintCricle.setColor(Color.BLACK);
mPaintCricle.setStrokeWidth(10);
mPaintCricle.setStyle(Paint.Style.STROKE);//圆形画笔空心

mPaintText=new Paint();
mPaintText.setColor(Color.BLACK);
mPaintText.setTextSize(30);//字体画笔设置字体大小
mPaintText.setTextAlign(Paint.Align.CENTER);//让字体居中显示

mCalendar=Calendar.getInstance();

handler.sendEmptyMessage(UPDATE_TIME);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//先画一个圆,调用canvas的drawCircle方法,第一个参数为圆心的横坐标,第二个参数为圆心纵坐标,第三个参数为半径,第四个参数为画笔
canvas.drawCircle(width/2,height/2,300,mPaintCricle);
//划出12个表示小时的线
for (int i=1;i<=12;i++){
canvas.rotate(30,width/2,height/2);//画布旋转30度
canvas.drawLine(width/2,height/2-300,width/2,height/2-280,mPaintLine);
canvas.drawText(""+i,width/2,height/2-250,mPaintText);
}
//划出表示分钟的60个点
for (int i=0;i<60;i++){
canvas.rotate(6,width/2,height/2);
canvas.drawLine(width/2,height/2-300,width/2,height/2-290,mPaintLine);
}
//用Calendar类得到当前的小时分钟秒
int minute=mCalendar.get(Calendar.MINUTE);
int hour=mCalendar.get(Calendar.HOUR);
int second=mCalendar.get(Calendar.SECOND);
//然后得到当前的时间时针分针秒针需要旋转的角度
float minDegree=minute/60f*360;
float hourDegree=(hour*60+minute)/12f/60*360;
float secondDegree=second/60f*360;

canvas.save();//保存当前状态
canvas.rotate(hourDegree,width/2,height/2);
canvas.drawLine(width/2,height/2-150,width/2,height/2+10,mPaintLine);
canvas.restore();//返回之前保存的状态

canvas.save();
canvas.rotate(minDegree,width/2,height/2);
canvas.drawLine(width/2,height/2-200,width/2,height/2+15,mPaintLine);
canvas.restore();

canvas.save();
canvas.rotate(secondDegree,width/2,height/2);
canvas.drawLine(width/2,height/2-230,width/2,height/2+20,mPaintSecondLine);
canvas.restore();
}
}


在XML文件中定义一下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<com.example.administrator.myselfview.view.MyAlarmview
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>


由于是自定义控件,所以要写全名

然后MainActivity中不需要多写什么,只需加入这个界面就行。

继承自View之后需要重写其构造器,View有四个构造器,这里重写其前两个构造器,并在第二个构造器中定义自定义的画笔。然后重写onMeasure()和onDraw()方法,在onMeasure()方法中定义画布的宽和高,这里使用的是系统定义的画布的大小;然后在onDraw()方法中进行对画布的操作,即作图。最后利用Handler类来对信息进行处理,使用 invalidate()对画布进行重画刷新操作。

进度条

这里做了三个简单的进度条,方法都一样,为圆形扩散型进度条,矩形填充进度条,弧形旋转进度条

圆形进度条

同样首先需要新建一个自定义控件的类并继承自View,并重写其两个构造器和两个方法

package com.example.administrator.myselfview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
* Created by Administrator on 2015/9/16.
*/
public class MyProgressBallView extends View{
private int width;
private int height;
private Paint mPaintBack;
private Paint mPaintCurrent;
private Paint mPaintText;
private int maxProgress=100;
private int currentProgress;

public void setCurrentProgress(int currentProgress) {
this.currentProgress = currentProgress;

}

public MyProgressBallView(Context context) {
super(context);
}

public MyProgressBallView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaintBack=new Paint();
mPaintBack.setColor(Color.GRAY);
mPaintBack.setAntiAlias(true);

mPaintCurrent=new Paint();
mPaintCurrent.setColor(Color.GREEN);
mPaintCurrent.setAntiAlias(true);

mPaintText=new Paint();
mPaintText.setColor(Color.BLUE);
mPaintText.setTextSize(80);
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);
invalidate();//重新绘制
canvas.drawCircle(width/2,height/2,300,mPaintBack);//最底下作为背景的圆
canvas.drawCircle(width/2,height/2,currentProgress*300f/maxProgress,mPaintCurrent);
//根据进度实时更新画出的表示进度的圆
canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
}//文本画笔实时更新表示下载进度
}


在自定义View中千万不要忘记每次都要重新绘制,即invalidate();要不然界面是不会动的。

然后在Activity中简单的模仿一个下载进度,并把当前进度传递到自定义View类中来,好实时地重绘到屏幕上。

package com.example.administrator.myselfview.subactivity;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.administrator.myselfview.R;
import com.example.administrator.myselfview.view.MyProgressBallView;

/**
* Created by Administrator on 2015/9/16.
*/
public class ProgressBallActivity extends Activity {
private MyProgressBallView myProgressBallView;
private Button mButton_start;
private int count=0;
private static final int PROGRESSBALL=121;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case PROGRESSBALL:
count++;
if (count<=100){
myProgressBallView.setCurrentProgress(count);
handler.sendEmptyMessageDelayed(PROGRESSBALL, 150);

}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progressball);
mButton_start= (Button) findViewById(R.id.button_progress_ball_start);
myProgressBallView= (MyProgressBallView) findViewById(R.id.progress_ball);
mButton_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.sendEmptyMessage(PROGRESSBALL);
}
});
}
}


利用Handler类通过子线程控制UI,设置当前进度。

然后在XML文件中声明

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_progress_ball_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始下载"/>
<com.example.administrator.myselfview.view.MyProgressBallView
android:id="@+id/progress_ball"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>


这里定义自定义控件的时候,切记一定要写全名

弧形进度条

弧形进度条跟圆形是一样,只不过是绘制图形的时候用到的方法不一样而已,其他完全相同,这里只写绘制时候的代码

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
invalidate();
canvas.drawArc(new RectF(width/2-300,height/2-300,width/2+300,height/2+300),90f,360f,false,mPaintBack);
canvas.drawArc(new RectF(width/2-300,height/2-300,width/2+300,height/2+300),-90f,currentProgress*360f/maxProgress,false,mPaintCurrent);
canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
}


矩形进度条

同样,这里只是举出矩形进度条绘制时候的方法

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
invalidate();
canvas.drawRect(width/2-120,height/2-300,width/2+120,height/2+300,mPaintBack);
canvas.drawRect(width/2-120,height/2+300-currentProgress*600f/maxProgress,width/2+120,height/2+300,mPaintCurrent);
canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: