仿华为系统自带天气预报UI---线条圆圈控件

时间:2021-12-22 14:51:22

仿照华为手机的系统自带天气预报的UI天气数值显示部分

效果图:

仿华为系统自带天气预报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);
	}
}
希望对大家有用,欢迎拍砖,欢迎指正!