Android自定义控件——时钟、进度条
2015-09-17 09:23
441 查看
由于Android提供的空间有限,不能满足程序的需求,所以才有了自定义控件
在XML文件中定义一下
由于是自定义控件,所以要写全名
然后MainActivity中不需要多写什么,只需加入这个界面就行。
继承自View之后需要重写其构造器,View有四个构造器,这里重写其前两个构造器,并在第二个构造器中定义自定义的画笔。然后重写onMeasure()和onDraw()方法,在onMeasure()方法中定义画布的宽和高,这里使用的是系统定义的画布的大小;然后在onDraw()方法中进行对画布的操作,即作图。最后利用Handler类来对信息进行处理,使用 invalidate()对画布进行重画刷新操作。
在自定义View中千万不要忘记每次都要重新绘制,即invalidate();要不然界面是不会动的。
然后在Activity中简单的模仿一个下载进度,并把当前进度传递到自定义View类中来,好实时地重绘到屏幕上。
利用Handler类通过子线程控制UI,设置当前进度。
然后在XML文件中声明
这里定义自定义控件的时候,切记一定要写全名
时钟
首先要写一个类继承自Viewpackage 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); }
相关文章推荐
- Android绘图:自定义View之——矩形进度条、圆环进度条、填充型进度条、时钟
- Android事件分发机制
- Android事件分发机制
- android Spinner控件详解
- 【Android应用开发】分享一个录制 Android 屏幕 gif 格式的小技巧
- 【Android应用开发】分享一个录制 Android 屏幕 gif 格式的小技巧
- (转载)android:visibility和android:scaleType 属性
- 浅谈android中如何在两个Activity之间互传数据
- android apk --- Active的生命周期
- 详解Android中AsyncTask的使用
- android端读取本地图片出现OutOfMemoryException
- [转]Android中的android:layout_width和android:width
- [Android]异步任务AsyncTask使用解析
- Android shape的使用
- Android笔记(三十一)Android中线程之间的通信(三)子线程给主线程发送消息
- Android中dip、dp、sp、pt和px的区别
- Android屏幕关闭时开机CPU运行(以传感器为例)
- Android开发之Service
- Android常用知识点总汇
- 部分android小知识点记录