仿照华为手机的系统自带天气预报的UI天气数值显示部分
效果图:
橙色部分是有渐变效果,图片上不大看的出来了,上面浅一点,下面深一点。
原理其实就是花了很多条短线:根据圆心和半径来确定每条线的x,y终点坐标,以及根据圆心和(半径-短线长度)来确定每条线的x,y起点坐标,然后起点到终点画线就可以了。
主要用到点三角函数的知识:
<span style="white-space:pre"> </span>/** * 根据半径和角度计算x坐标 */ private float calculateX(float r, double angle) { angle = angle * ((2 * Math.PI) / 360); Log.i(TAG, "angle = " + angle + ",Math.sin(angle) = " + Math.sin(angle)); double x = r * Math.sin(angle); double xFinal = centerX + x; return (float) xFinal; } /** * 根据半径和角度计算y坐标 */ private float calculateY(float r, double angle) { angle = angle * ((2 * Math.PI) / 360); Log.i(TAG, "angle = " + angle + ",Math.cos(angle) = " + Math.cos(angle)); double y = r * Math.cos(angle); double yFinal = centerY - y; return (float) yFinal; }主要用到的类也就是Canvas、Paint、Matrix、SweepGradient(扫描渐变渲染效果)
贴上代码:
package com.cc.test.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Shader; import android.graphics.SweepGradient; import android.graphics.Typeface; import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * 线条圆圈控件(仿华为系统天气预报UI) * @author zhangyu * @date 2016-4-1 */ public class LineCircle extends View { private static final String TAG = "LineCircle"; private float centerX, centerY; private int viewWidth, viewHeight; private Paint linePaint; private TextPaint whitePaint; // 有渐变颜色的旋转起止角度 private float startAngle = 21, stopAngle = 123; // 圆半径 线长度 private float r, l; private Shader shader, shaderWhite; //起止温度 private int startTem = 19,stopTem = 24; public LineCircle(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public LineCircle(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public LineCircle(Context context) { super(context); init(context); } private void init(Context context) { linePaint = new Paint(); linePaint.setStrokeWidth(3); linePaint.setAntiAlias(true); whitePaint = new TextPaint(); whitePaint.setColor(Color.WHITE); whitePaint.setStrokeWidth(4); whitePaint.setAntiAlias(true); } /** * 设置开始角度 * 开始与结束角度内显示为渐变彩色,反映当前温度范围. * @param startAngle 开始角度 * @return 设置成功返回true 否则返回false */ public boolean setStartAngle(float startAngle){ if(startAngle >= 0 && startAngle <= 360){ this.startAngle = startAngle; invalidate(); return true; }else return false; } /** * 设置结束角度 * 开始与结束角度内显示为渐变彩色,反映当前温度范围. * @param stopAngle 结束角度 * @return 设置成功返回true 否则返回false */ public boolean setStopAngle(float stopAngle){ if(stopAngle >= 0 && stopAngle <= 360){ this.stopAngle = stopAngle; invalidate(); return true; }else return false; } /** * 设置起始温度 * @param startTem */ public void setStartTem(int startTem){ this.startTem = startTem; invalidate(); } /** * 设置截止温度 * @param stopTem */ public void setStopTem(int stopTem){ this.stopTem = stopTem; invalidate(); } @Override protected void onDraw(Canvas canvas) { for (double angle = 0; angle <= 360d; angle += 3.0d) { float xStart = calculateX(r, angle); float xStop = calculateX(r - l, angle); float yStart = calculateY(r, angle); float yStop = calculateY(r - l, angle); if (angle <= stopAngle && angle >= startAngle) { linePaint.setShader(shader); } else linePaint.setShader(shaderWhite); if (angle == 204 || angle == 156) { linePaint.setStrokeWidth(2); float xStartL = calculateX(r * 1.05f, angle); float xStopL = calculateX((r - l), angle); float yStartL = calculateY(r * 1.05f, angle); float yStopL = calculateY((r - l), angle); canvas.drawLine(xStartL, yStartL, xStopL, yStopL, linePaint); //底部两条较长的线 } else if (!(angle < 204 && angle > 156)) { linePaint.setStrokeWidth(3); canvas.drawLine(xStart, yStart, xStop, yStop, linePaint); // 画短线 } Log.d(TAG, "angle = " + angle + ",xStart = " + xStart + ",xStop = " + xStop + ",yStart = " + yStart + ",yStop = " + yStop); } drawCenterTem(canvas); drawStartTem(canvas); drawStopTem(canvas); super.onDraw(canvas); } /** * 根据半径和角度计算x坐标 */ private float calculateX(float r, double angle) { angle = angle * ((2 * Math.PI) / 360); Log.i(TAG, "angle = " + angle + ",Math.sin(angle) = " + Math.sin(angle)); double x = r * Math.sin(angle); double xFinal = centerX + x; return (float) xFinal; } /** * 根据半径和角度计算y坐标 */ private float calculateY(float r, double angle) { angle = angle * ((2 * Math.PI) / 360); Log.i(TAG, "angle = " + angle + ",Math.cos(angle) = " + Math.cos(angle)); double y = r * Math.cos(angle); double yFinal = centerY - y; return (float) yFinal; } /** * 画中心位置温度 * * @param canvas */ private void drawCenterTem(Canvas canvas) { whitePaint.setTextSize(r * 0.6f); whitePaint.setTypeface(Typeface.DEFAULT); canvas.drawText("24°", (centerX - r * 0.35f), (centerY + r * 0.3f), whitePaint); } /** * 画起始温度 */ private void drawStartTem(Canvas canvas) { whitePaint.setTextSize(r * 0.1f); canvas.drawText(startTem + "°", calculateX(r * 1.05f, startAngle), calculateY(r * 1.05f, startAngle), whitePaint); } /** * 画截至温度 */ private void drawStopTem(Canvas canvas) { whitePaint.setTextSize(r * 0.1f); canvas.drawText(stopTem + "°", calculateX(r * 1.05f, stopAngle), calculateY(r * 1.05f, stopAngle), whitePaint); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { viewWidth = getWidth(); viewHeight = getHeight(); centerX = viewWidth / 2f; centerY = viewHeight / 2f; r = viewWidth * 0.4f; l = viewWidth * 0.05f; Log.v(TAG, "centerX = " + centerX + ",centerY = " + centerY); /* 设置渐变色 */ shader = new SweepGradient(centerX, centerY, new int[] { Color.parseColor("#FFDAB5"), Color.parseColor("#E87400") }, null); shaderWhite = new SweepGradient(centerX, centerY, new int[] { Color.WHITE, Color.WHITE }, null); Matrix matrix = new Matrix(); // 使用matrix改变渐变色起始位置,默认是在90度位置 matrix.setRotate(45, centerX, centerY); shader.setLocalMatrix(matrix); linePaint.setShader(shader); invalidate(); super.onWindowFocusChanged(hasWindowFocus); } }希望对大家有用,欢迎拍砖,欢迎指正!