标签:
前言
顾名思义,就是在Android手机屏幕中绘制我们需要的内容,根据绘制内容的大小(measure),布局(layout)来讲具体内容展示在屏幕中,通过绘制(draw)来实现我们需要的效果.
measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:
(1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;
(2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:
(1)绘制背景;
(2)如果要视图显示渐变框,这里会做一些准备工作;
(3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;
(4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;
(5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;
(6)绘制滚动条;
从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。
参考:http://blog.csdn.net/xu_fu/article/details/7829721
基于Android SDK内部自己提供,也是我们学习的主要内容,2D绘图的api大部分是android.graphics和android.graphics.drawable包中,他们提供了Canvas,ColorFilter,Point和RetcF等,以及一些动画相关的:AnimationDrawable,BitmapDrawable和TransitionDrawable等.
用Open GL ES 1.0
参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html
通过canvas对象可以绘制的[弧线],[Bitmap],[圆],[点],[矩形],[圆角矩形],[文本],[路径]等图形,其次还提供了旋转(rotate),缩放(scale),渐变(translate)和扭曲(skew)等转换方法.
private Paint mPaintRing;// 圆环画笔 private Paint mPaintDegree;// 刻度/圆心画笔 private Paint mPaintText;// 文字画笔 private float strokeWidthText = 2;// 文字画笔厚度 private float strokeWidthRing = 4;// 圆环画笔厚度 private float radius = 0;// 圆环半径 //用于初始化时间的角度设置 private float hourDegree = 0;// 时针角度 private float minuteDegree = 0;// 分针角度 private float secondDegree = 0;// 秒针角度 private Date mCurrentDate=null;// 用户设置时间,默认为当前时间
private void initPaint() { mCurrentDate=new Date(); setDate(mCurrentDate); // 初始化圆环画笔 mPaintRing = new Paint(); mPaintRing.setColor(Color.RED); mPaintRing.setStyle(Paint.Style.STROKE); mPaintRing.setStrokeWidth(strokeWidthRing); mPaintRing.setAntiAlias(true); // 初始化刻度画笔 mPaintDegree = new Paint(); mPaintDegree.setColor(Color.RED); mPaintDegree.setStyle(Paint.Style.FILL); mPaintDegree.setAntiAlias(true); // 初始化文字画笔 mPaintText = new Paint(); mPaintText.setColor(Color.RED); mPaintText.setStyle(Paint.Style.FILL); mPaintText.setAntiAlias(true); mPaintText.setStrokeWidth(strokeWidthText); }
//初始化半径,由于圆环的厚度也要占据一定的宽度,因此需要减除厚度值,这样才能保证圆环 radius = Math.min(getWidth() / 2, getHeight() / 2) - strokeWidthRing; // 1.画圆环 canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaintRing); // 2.画刻度 drawMark(canvas); // 3.画圆心 canvas.drawCircle(getWidth() / 2, getHeight() / 2, 5, mPaintDegree); // 4.移动坐标中心到画布中心 canvas.save(); canvas.translate(getWidth() / 2, getHeight() / 2); canvas.save(); // 5.画时针 drawHourMark(hourDegree, canvas); // 6.画分针 drawMinuteMark(minuteDegree, canvas); // 7.画秒针 drawSecondMark(secondDegree, canvas); // 8.画时间文字 mPaintText.setTextSize(30); mPaintText.setTextAlign(Paint.Align.CENTER); canvas.drawText(XDate.fmtDate(mCurrentDate,"HH:mm:ss"), 0, -20, mPaintText);
/** * 绘图基础-时钟<br> * 博客:<a href="http://blog.csdn.net/qq243223991">安前松博客</a> */ public class ClockView extends View { private Paint mPaintRing;// 圆环画笔 private Paint mPaintDegree;// 刻度/圆心画笔 private Paint mPaintText;// 文字画笔 private float strokeWidthText = 2;// 文字画笔厚度 private float strokeWidthRing = 4;// 圆环画笔厚度 private float radius = 0;// 圆环半径 //用于初始化时间的角度设置 private float hourDegree = 0;// 时针角度 private float minuteDegree = 0;// 分针角度 private float secondDegree = 0;// 秒针角度 private Date mCurrentDate=null;// 用户设置时间,默认为当前时间 private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what==0){ long times=mCurrentDate.getTime(); mCurrentDate.setTime(times+1000); setDate(mCurrentDate); handler.sendEmptyMessageDelayed(0,1000); } } }; public ClockView(Context context) { super(context); initPaint(); } public ClockView(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int min = Math.min(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));// 防止圆形变形,宽高度必须相等 setMeasuredDimension(min, min);// 重新设置宽高 } /** * 根据默认宽度测量宽度 * * @param measureSpec * @return */ private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * 根据默认高度测量高度 * * @param measureSpec * @return */ private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } private void initPaint() { mCurrentDate=new Date(); setDate(mCurrentDate); // 初始化圆环画笔 mPaintRing = new Paint(); mPaintRing.setColor(Color.RED); mPaintRing.setStyle(Paint.Style.STROKE); mPaintRing.setStrokeWidth(strokeWidthRing); mPaintRing.setAntiAlias(true); // 初始化刻度画笔 mPaintDegree = new Paint(); mPaintDegree.setColor(Color.RED); mPaintDegree.setStyle(Paint.Style.FILL); mPaintDegree.setAntiAlias(true); // 初始化文字画笔 mPaintText = new Paint(); mPaintText.setColor(Color.RED); mPaintText.setStyle(Paint.Style.FILL); mPaintText.setAntiAlias(true); mPaintText.setStrokeWidth(strokeWidthText); } @Override protected void onDraw(Canvas canvas) { //初始化半径,由于圆环的厚度也要占据一定的宽度,因此需要减除厚度值,这样才能保证圆环 radius = Math.min(getWidth() / 2, getHeight() / 2) - strokeWidthRing; // 1.画圆环 canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaintRing); // 2.画刻度 drawMark(canvas); // 3.画圆心 canvas.drawCircle(getWidth() / 2, getHeight() / 2, 5, mPaintDegree); // 4.移动坐标中心到画布中心 canvas.save(); canvas.translate(getWidth() / 2, getHeight() / 2); canvas.save(); // 5.画时针 drawHourMark(hourDegree, canvas); // 6.画分针 drawMinuteMark(minuteDegree, canvas); // 7.画秒针 drawSecondMark(secondDegree, canvas); // 8.画时间文字 mPaintText.setTextSize(30); mPaintText.setTextAlign(Paint.Align.CENTER); canvas.drawText(XDate.fmtDate(mCurrentDate,"HH:mm:ss"), 0, -20, mPaintText); } /** * 画时针 * * @param degree * @param canvas */ private void drawHourMark(float degree, Canvas canvas) { canvas.rotate(degree);// 旋转度数 mPaintDegree.setStrokeWidth(6); canvas.drawLine(0, 0, 0, -radius / 2, mPaintDegree); canvas.restore(); canvas.save(); } /** * 画分针 * * @param degree * @param canvas */ private void drawMinuteMark(float degree, Canvas canvas) { canvas.rotate(degree);// 旋转度数 mPaintDegree.setStrokeWidth(3); canvas.drawLine(0, 0, 0, -radius / 2 - 25, mPaintDegree); canvas.restore(); canvas.save(); } /** * 画秒针 * * @param degree * @param canvas */ private void drawSecondMark(float degree, Canvas canvas) { canvas.rotate(degree);// 旋转度数 mPaintDegree.setStrokeWidth(2); canvas.drawLine(0, 0, 0, -radius / 2 - 40, mPaintDegree); canvas.restore(); canvas.save(); } /** * 画刻度 */ private void drawMark(Canvas canvas) { for (int i = 0; i < 60; i++) { if (i % 5 == 0) { mPaintDegree.setStrokeWidth(strokeWidthRing); canvas.drawLine(getWidth() / 2, strokeWidthRing, getWidth() / 2, 40, mPaintDegree); mPaintText.setTextAlign(Paint.Align.CENTER); mPaintText.setTextSize(20); if (i / 5 == 0) { canvas.drawText("12", getWidth() / 2, 60, mPaintText); } else { canvas.drawText(i / 5 + "", getWidth() / 2, 60, mPaintText); } } else { mPaintDegree.setStrokeWidth(2); canvas.drawLine(getWidth() / 2, strokeWidthRing, getWidth() / 2, 30, mPaintDegree); } canvas.rotate(6, getWidth() / 2, getHeight() / 2); } } /** * 设置时间 * * @param date */ public void setDate(@NonNull Date date) { mCurrentDate=date; float hourDegree = getHourDegree(getHours(date), getMinutes(date), getSeconds(date)); float minuteDegree = getMinuteDegree(getMinutes(date), getSeconds(date)); float secondDegree = getSecondDegree(getSeconds(date)); rotate(hourDegree, minuteDegree, secondDegree); } /** * 设置时间戳 * * @param timeMills */ public void setTimeMills(long timeMills) { Date date = new Date(); date.setTime(timeMills); setDate(date); } /** * 开始时间旋转 */ public void start(){ handler.sendEmptyMessageDelayed(0,1000); } /** * 旋转 */ private void rotate(float hourDegree, float minuteDegree, float secondDegree) { this.hourDegree = hourDegree; this.minuteDegree = minuteDegree; this.secondDegree = secondDegree; invalidate(); } /** * 根据小时获取角度 * * @param hour * @return */ private float getHourDegree(int hour, int minute, int second) { float hourDegree = (hour + minute / 60.0f + second / 3600.0f) * 30; return hourDegree; } /** * 根据分钟获取角度 * * @param minute * @return */ private float getMinuteDegree(int minute, int second) { float minuteDegree = (minute + second / 60.0f) * 6; return minuteDegree; } /** * 根据秒钟获取角度 * * @param second * @return */ private float getSecondDegree(int second) { int secondDegree = second * 6; return secondDegree; } /** * 获取时间信息 * * @param date * @return */ private HashMap<Integer, Integer> getTime(Date date) { HashMap<Integer, Integer> time = new HashMap<>(); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); time.put(Calendar.HOUR, calendar.get(Calendar.HOUR));//12小时制 time.put(Calendar.MINUTE, calendar.get(Calendar.MINUTE)); time.put(Calendar.SECOND, calendar.get(Calendar.SECOND)); return time; } /** * 获取当天中小时 * * @param date * @return */ private int getHours(Date date) { return getTime(date).get(Calendar.HOUR); } /** * 获取分钟 * * @param date * @return */ private int getMinutes(Date date) { return getTime(date).get(Calendar.MINUTE); } /** * 获取秒钟 * * @param date * @return */ private int getSeconds(Date date) { return getTime(date).get(Calendar.SECOND); } }
标签:
原文地址:http://blog.csdn.net/qq243223991/article/details/52300382