Android之自定义View以及画一个时钟

原文
http://www.2cto.com/kf/201509/443112.html

Android自带的View满足不了开发者时,自定义View就发挥了很好的作用。
建立一个自定义View,需要继承于View类,并且实现其中的至少一个构造函数和两个方法:onMeasure()和onDraw();
onMeasure()用于设置自定义View的尺寸,onDraw()用于绘制View中的内容。

在onDraw()方法中,需要调用画笔绘制图形或文本,绘制的模板时Canvas对象, Canvas类中用来绘制图形文本的方法有:

drawRect(RectF rect, Paint paint) //绘制区域,参数一为RectF一个区域

drawPath(Path path, Paint paint) //绘制一个路径,参数一为Path路径对象

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) //贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap),参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象,因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。

drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) //画线,参数一起始点的x轴位置,参数二起始点的y轴位置,参数三终点的x轴水平位置,参数四y轴垂直位置,最后一个参数为Paint 画刷对象。

drawPoint(float x, float y, Paint paint) //画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。

drawText(String text, float x, floaty, Paint paint) //渲染文本,Canvas类除了上面的还可以描绘文字,参数一是String类型的文本,参数二x轴,参数三y轴,参数四是Paint对象。

drawOval(RectF oval, Paint paint)//画椭圆,参数一是扫描区域,参数二为paint对象;

drawCircle(float cx, float cy, float radius,Paint paint)// 绘制圆,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,参数二是起始角(度)在电弧的开始,参数三扫描角(度)开始顺时针测量的,参数四是如果这是真的话,包括椭圆中心的电弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象。

绘制图形需要画笔Paint对象,Paint类中的方法有:

setARGB(int a, int r, int g, int b) // 设置 Paint对象颜色,参数一为alpha透明值

setAlpha(int a) // 设置alpha不透明度,范围为0~255

setAntiAlias(boolean aa) // 是否抗锯齿

setColor(int color) // 设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义

setTextScaleX(float scaleX) // 设置文本缩放倍数,1.0f为原始

setTextSize(float textSize) // 设置字体大小

setUnderlineText(booleanunderlineText) // 设置下划线

Demo

一个自定义时钟视图的写法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<code class = "language-java" hljs= "" > public class MyView extends View {
 
     private int width;
     private int height;
     private Paint mPaintLine;
     private Paint mPaintCircle;
     private Paint mPaintHour;
     private Paint mPaintMinute;
     private Paint mPaintSec;
     private Paint mPaintText;
     private Calendar mCalendar;
     public static final int NEED_INVALIDATE = 0X23 ;
 
     //每隔一秒,在handler中调用一次重新绘制方法
     private Handler handler = new Handler(){
         @Override
         public void handleMessage(Message msg) {
 
             switch (msg.what){
                 case NEED_INVALIDATE:
                     mCalendar = Calendar.getInstance();
                     invalidate(); //告诉UI主线程重新绘制
                     handler.sendEmptyMessageDelayed(NEED_INVALIDATE, 1000 );
                     break ;
                 default :
                     break ;
             }
         }
     };
 
     public MyView(Context context) {
         super (context);
     }
 
     public MyView(Context context, AttributeSet attrs) {
         super (context, attrs);
 
         mCalendar = Calendar.getInstance();
 
         mPaintLine = new Paint();
         mPaintLine.setColor(Color.BLUE);
         mPaintLine.setStrokeWidth( 10 );
 
         mPaintCircle = new Paint();
         mPaintCircle.setColor(Color.GREEN); //设置颜色
         mPaintCircle.setStrokeWidth( 10 ); //设置线宽
         mPaintCircle.setAntiAlias( true ); //设置是否抗锯齿
         mPaintCircle.setStyle(Paint.Style.STROKE); //设置绘制风格
 
         mPaintText = new Paint();
         mPaintText.setColor(Color.BLUE);
         mPaintText.setStrokeWidth( 10 );
         mPaintText.setTextAlign(Paint.Align.CENTER);
         mPaintText.setTextSize( 40 );
 
         mPaintHour = new Paint();
         mPaintHour.setStrokeWidth( 20 );
         mPaintHour.setColor(Color.BLUE);
 
         mPaintMinute = new Paint();
         mPaintMinute.setStrokeWidth( 15 );
         mPaintMinute.setColor(Color.BLUE);
 
         mPaintSec = new Paint();
         mPaintSec.setStrokeWidth( 10 );
         mPaintSec.setColor(Color.BLUE);
 
         handler.sendEmptyMessage(NEED_INVALIDATE); //向handler发送一个消息,让它开启重绘
     }
 
     @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);
 
         int circleRadius = 400 ;
         //画出大圆
         canvas.drawCircle(width / 2 , height / 2 , circleRadius, mPaintCircle);
         //画出圆中心
         canvas.drawCircle(width / 2 , height / 2 , 20 , mPaintCircle);
         //依次旋转画布,画出每个刻度和对应数字
         for ( int i = 1 ; i <= 12 ; i++) {
             canvas.save(); //保存当前画布
             canvas.rotate( 360 / 12 *i,width/ 2 ,height/ 2 );
             //左起:起始位置x坐标,起始位置y坐标,终止位置x坐标,终止位置y坐标,画笔(一个Paint对象)
             canvas.drawLine(width / 2 , height / 2 - circleRadius, width / 2 , height / 2 - circleRadius + 30 , mPaintCircle);
             //左起:文本内容,起始位置x坐标,起始位置y坐标,画笔
             canvas.drawText(+i, width / 2 , height / 2 - circleRadius + 70 , mPaintText);
             canvas.restore(); //
         }
 
         int minute = mCalendar.get(Calendar.MINUTE); //得到当前分钟数
         int hour = mCalendar.get(Calendar.HOUR); //得到当前小时数
         int sec = mCalendar.get(Calendar.SECOND); //得到当前秒数
 
         float minuteDegree = minute/60f* 360 ; //得到分针旋转的角度
         canvas.save();
         canvas.rotate(minuteDegree, width / 2 , height / 2 );
         canvas.drawLine(width / 2 , height / 2 - 250 , width / 2 , height / 2 + 40 , mPaintMinute);
         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 - 200 , width / 2 , height / 2 + 30 , mPaintHour);
         canvas.restore();
 
         float secDegree = sec/60f* 360 ; //得到秒针旋转的角度
         canvas.save();
         canvas.rotate(secDegree,width/ 2 ,height/ 2 );
         canvas.drawLine(width/ 2 ,height/ 2 - 300 ,width/ 2 ,height/ 2 + 40 ,mPaintSec);
         canvas.restore();
 
     }
}</code>

需要在布局中加载自定义View,名字必须是全名(包括包名):
activity_timer

?
1
2
3
4
<code class = "language-xml" hljs= "" ><!--?xml version= 1.0 encoding=utf- 8 ?-->
<linearlayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:orientation= "vertical" xmlns:android= "http://schemas.android.com/apk/res/android" >
     <com.example.administrator.selfdefinedview.widget.myview android:layout_height= "match_parent/" android:layout_width= "match_parent" >
</com.example.administrator.selfdefinedview.widget.myview></linearlayout></code>

主活动setContentView就行了

?
1
2
3
4
5
6
7
8
<code class = "language-java" hljs= "" > public class TimerActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_timer);
     }
}</code>

演示结果:
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安果移不动

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值