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

来源:互联网 发布:高压清洗机品牌 知乎 编辑:程序博客网 时间:2024/06/06 06:36

原文
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
<codeclass="language-java"hljs="">publicclassMyView extendsView {
 
    privateintwidth;
    privateintheight;
    privatePaint mPaintLine;
    privatePaint mPaintCircle;
    privatePaint mPaintHour;
    privatePaint mPaintMinute;
    privatePaint mPaintSec;
    privatePaint mPaintText;
    privateCalendar mCalendar;
    publicstaticfinal int NEED_INVALIDATE = 0X23;
 
    //每隔一秒,在handler中调用一次重新绘制方法
    privateHandler handler = newHandler(){
        @Override
        publicvoidhandleMessage(Message msg) {
 
            switch(msg.what){
                caseNEED_INVALIDATE:
                    mCalendar = Calendar.getInstance();
                    invalidate();//告诉UI主线程重新绘制
                    handler.sendEmptyMessageDelayed(NEED_INVALIDATE,1000);
                    break;
                default:
                    break;
            }
        }
    };
 
    publicMyView(Context context) {
        super(context);
    }
 
    publicMyView(Context context, AttributeSet attrs) {
        super(context, attrs);
 
        mCalendar = Calendar.getInstance();
 
        mPaintLine = newPaint();
        mPaintLine.setColor(Color.BLUE);
        mPaintLine.setStrokeWidth(10);
 
        mPaintCircle = newPaint();
        mPaintCircle.setColor(Color.GREEN);//设置颜色
        mPaintCircle.setStrokeWidth(10);//设置线宽
        mPaintCircle.setAntiAlias(true);//设置是否抗锯齿
        mPaintCircle.setStyle(Paint.Style.STROKE);//设置绘制风格
 
        mPaintText = newPaint();
        mPaintText.setColor(Color.BLUE);
        mPaintText.setStrokeWidth(10);
        mPaintText.setTextAlign(Paint.Align.CENTER);
        mPaintText.setTextSize(40);
 
        mPaintHour = newPaint();
        mPaintHour.setStrokeWidth(20);
        mPaintHour.setColor(Color.BLUE);
 
        mPaintMinute = newPaint();
        mPaintMinute.setStrokeWidth(15);
        mPaintMinute.setColor(Color.BLUE);
 
        mPaintSec = newPaint();
        mPaintSec.setStrokeWidth(10);
        mPaintSec.setColor(Color.BLUE);
 
        handler.sendEmptyMessage(NEED_INVALIDATE);//向handler发送一个消息,让它开启重绘
    }
 
    @Override
    protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }
 
    @Override
    protectedvoidonDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        intcircleRadius = 400;
        //画出大圆
        canvas.drawCircle(width / 2, height / 2, circleRadius, mPaintCircle);
        //画出圆中心
        canvas.drawCircle(width / 2, height / 2,20, mPaintCircle);
        //依次旋转画布,画出每个刻度和对应数字
        for(inti = 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();//
        }
 
        intminute = mCalendar.get(Calendar.MINUTE);//得到当前分钟数
        inthour = mCalendar.get(Calendar.HOUR);//得到当前小时数
        intsec = mCalendar.get(Calendar.SECOND);//得到当前秒数
 
        floatminuteDegree = 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();
 
        floathourDegree = (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();
 
        floatsecDegree = 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
<codeclass="language-xml"hljs=""><!--?xml version=1.0encoding=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
<codeclass="language-java"hljs="">publicclassTimerActivity extendsActivity {
 
    @Override
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
    }
}</code>

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

0 0
原创粉丝点击