Android 天气APP(二十七)增加地图天气的逐小时天气、太阳和月亮数据
imageId = R.mipmap.icon_213d;
break;
case “300”:
imageId = R.mipmap.icon_300d;
break;
case “301”:
imageId = R.mipmap.icon_301d;
break;
case “302”:
imageId = R.mipmap.icon_302d;
break;
case “303”:
imageId = R.mipmap.icon_303d;
break;
case “304”:
imageId = R.mipmap.icon_304d;
break;
case “305”:
imageId = R.mipmap.icon_305d;
break;
case “306”:
imageId = R.mipmap.icon_306d;
break;
case “307”:
imageId = R.mipmap.icon_307d;
break;
case “308”:
imageId = R.mipmap.icon_308d;
break;
case “309”:
imageId = R.mipmap.icon_309d;
break;
case “310”:
imageId = R.mipmap.icon_310d;
break;
case “311”:
imageId = R.mipmap.icon_311d;
break;
case “312”:
imageId = R.mipmap.icon_312d;
break;
case “313”:
imageId = R.mipmap.icon_313d;
break;
case “314”:
imageId = R.mipmap.icon_314d;
break;
case “315”:
imageId = R.mipmap.icon_315d;
break;
case “316”:
imageId = R.mipmap.icon_316d;
break;
case “317”:
imageId = R.mipmap.icon_317d;
break;
case “318”:
imageId = R.mipmap.icon_318d;
break;
case “399”:
imageId = R.mipmap.icon_399d;
break;
case “400”:
imageId = R.mipmap.icon_400d;
break;
case “401”:
imageId = R.mipmap.icon_401d;
break;
case “402”:
imageId = R.mipmap.icon_402d;
break;
case “403”:
imageId = R.mipmap.icon_403d;
break;
case “404”:
imageId = R.mipmap.icon_404d;
break;
case “405”:
imageId = R.mipmap.icon_405d;
break;
case “406”:
imageId = R.mipmap.icon_406d;
break;
case “407”:
imageId = R.mipmap.icon_407d;
break;
case “408”:
imageId = R.mipmap.icon_408d;
break;
case “409”:
imageId = R.mipmap.icon_409d;
break;
case “410”:
imageId = R.mipmap.icon_410d;
break;
case “499”:
imageId = R.mipmap.icon_499d;
break;
case “500”:
imageId = R.mipmap.icon_500d;
break;
case “501”:
imageId = R.mipmap.icon_501d;
break;
case “502”:
imageId = R.mipmap.icon_502d;
break;
case “503”:
imageId = R.mipmap.icon_503d;
break;
case “504”:
imageId = R.mipmap.icon_504d;
break;
case “507”:
imageId = R.mipmap.icon_507d;
break;
case “508”:
imageId = R.mipmap.icon_508d;
break;
case “509”:
imageId = R.mipmap.icon_509d;
break;
case “510”:
imageId = R.mipmap.icon_510d;
break;
case “511”:
imageId = R.mipmap.icon_511d;
break;
case “512”:
imageId = R.mipmap.icon_512d;
break;
case “513”:
imageId = R.mipmap.icon_513d;
break;
case “514”:
imageId = R.mipmap.icon_514d;
break;
case “515”:
imageId = R.mipmap.icon_515d;
break;
case “900”:
imageId = R.mipmap.icon_900d;
break;
case “901”:
imageId = R.mipmap.icon_901d;
break;
case “999”:
imageId = R.mipmap.icon_999d;
break;
default:
imageId = R.mipmap.icon_100d;
break;
}
return imageId;
}
/**
- 获取晚上深色天气图标
*/
public static int getNightIconDark(String weather) {
int imageId;
switch (weather) {
case “100”:
imageId = R.mipmap.icon_100n;
break;
case “101”:
imageId = R.mipmap.icon_101n;
break;
case “102”:
imageId = R.mipmap.icon_102n;
break;
case “103”:
imageId = R.mipmap.icon_103n;
break;
case “104”:
imageId = R.mipmap.icon_104n;
break;
case “200”:
imageId = R.mipmap.icon_200n;
break;
case “201”:
imageId = R.mipmap.icon_210n;
break;
case “202”:
imageId = R.mipmap.icon_202n;
break;
case “203”:
imageId = R.mipmap.icon_203n;
break;
case “204”:
imageId = R.mipmap.icon_204n;
break;
case “205”:
imageId = R.mipmap.icon_205n;
break;
case “206”:
imageId = R.mipmap.icon_206n;
break;
case “207”:
imageId = R.mipmap.icon_207n;
break;
case “208”:
imageId = R.mipmap.icon_208n;
break;
case “209”:
imageId = R.mipmap.icon_209n;
break;
case “210”:
imageId = R.mipmap.icon_210n;
break;
case “211”:
imageId = R.mipmap.icon_211n;
break;
case “212”:
imageId = R.mipmap.icon_212n;
break;
case “213”:
imageId = R.mipmap.icon_213n;
break;
case “300”:
imageId = R.mipmap.icon_300n;
break;
case “301”:
imageId = R.mipmap.icon_301n;
break;
case “302”:
imageId = R.mipmap.icon_302n;
break;
case “303”:
imageId = R.mipmap.icon_303n;
break;
case “304”:
imageId = R.mipmap.icon_304n;
break;
case “305”:
imageId = R.mipmap.icon_305n;
break;
case “306”:
imageId = R.mipmap.icon_306n;
break;
case “307”:
imageId = R.mipmap.icon_307n;
break;
case “308”:
imageId = R.mipmap.icon_308n;
break;
case “309”:
imageId = R.mipmap.icon_309n;
break;
case “310”:
imageId = R.mipmap.icon_310n;
break;
case “311”:
imageId = R.mipmap.icon_311n;
break;
case “312”:
imageId = R.mipmap.icon_312n;
break;
case “313”:
imageId = R.mipmap.icon_313n;
break;
case “314”:
imageId = R.mipmap.icon_314n;
break;
case “315”:
imageId = R.mipmap.icon_315n;
break;
case “316”:
imageId = R.mipmap.icon_316n;
break;
case “317”:
imageId = R.mipmap.icon_317n;
break;
case “318”:
imageId = R.mipmap.icon_318n;
break;
case “399”:
imageId = R.mipmap.icon_399n;
break;
case “400”:
imageId = R.mipmap.icon_400n;
break;
case “401”:
imageId = R.mipmap.icon_401n;
break;
case “402”:
imageId = R.mipmap.icon_402n;
break;
case “403”:
imageId = R.mipmap.icon_403n;
break;
case “404”:
imageId = R.mipmap.icon_404n;
break;
case “405”:
imageId = R.mipmap.icon_405n;
break;
case “406”:
imageId = R.mipmap.icon_406n;
break;
case “407”:
imageId = R.mipmap.icon_407n;
break;
case “408”:
imageId = R.mipmap.icon_408n;
break;
case “409”:
imageId = R.mipmap.icon_409n;
break;
case “410”:
imageId = R.mipmap.icon_410n;
break;
case “499”:
imageId = R.mipmap.icon_499n;
break;
case “500”:
imageId = R.mipmap.icon_500n;
break;
case “501”:
imageId = R.mipmap.icon_501n;
break;
case “502”:
imageId = R.mipmap.icon_502n;
break;
case “503”:
imageId = R.mipmap.icon_503n;
break;
case “504”:
imageId = R.mipmap.icon_504n;
break;
case “507”:
imageId = R.mipmap.icon_507n;
break;
case “508”:
imageId = R.mipmap.icon_508n;
break;
case “509”:
imageId = R.mipmap.icon_509n;
break;
case “510”:
imageId = R.mipmap.icon_510n;
break;
case “511”:
imageId = R.mipmap.icon_511n;
break;
case “512”:
imageId = R.mipmap.icon_512n;
break;
case “513”:
imageId = R.mipmap.icon_513n;
break;
case “514”:
imageId = R.mipmap.icon_514n;
break;
case “515”:
imageId = R.mipmap.icon_515n;
break;
case “900”:
imageId = R.mipmap.icon_900n;
break;
case “901”:
imageId = R.mipmap.icon_901n;
break;
case “999”:
imageId = R.mipmap.icon_999n;
break;
default:
imageId = R.mipmap.icon_100n;
break;
}
return imageId;
}
}
在com.llw.goodweather中新建view包,然后再建一个horizonview
下面一个一个来说明
先从接口来看
ScrollWatched.java
package com.llw.goodweather.view.horizonview;
/**
- 定义滑动监听接口
*/
public interface ScrollWatched {
void addWatcher(ScrollWatcher watcher);
void removeWatcher(ScrollWatcher watcher);
void notifyWatcher(int x);
}
ScrollWatcher.java
package com.llw.goodweather.view.horizonview;
/**
- 更新滑动
*/
public interface ScrollWatcher {
void update(int scrollX);
}
HourlyForecastView.java
package com.llw.goodweather.view.horizonview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.llw.goodweather.R;
import com.llw.goodweather.bean.HourlyResponse;
import com.llw.goodweather.utils.DisplayUtil;
import com.llw.goodweather.utils.IconUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
- 24小时天气预报自定义View
*/
public class HourlyForecastView extends View implements ScrollWatcher {
private Context mContext;
//折线
private Paint foldLinePaint;
private Paint backPaint;
//底线
private Paint baseLinePaint;
//虚线
private Paint dashPaint;
//文字
private Paint textPaint;
//图片
private Paint bitmapPaint;
//文本的大小
private int textSize;
//数据
private List<HourlyResponse.HourlyBean> hourlyWeatherList;
//画虚线的点的index
private List dashLineList;
private int screenWidth;
//每个item的宽度
private int itemWidth;
//温度基准高度
private int lowestTempHeight;
//温度基准高度
private int highestTempHeight;
//最低温
private int lowestTemp;
//最高温
private int highestTemp;
//默认图片绘制位置
float bitmapHeight;
//默认图片宽高
float bitmapXY;
//View宽高
private int mWidth;
private int mHeight;
//默认高
private int defHeightPixel = 0;
private int defWidthPixel = 0;
private int paddingL = 0;
private int paddingT = 0;
private int paddingR = 0;
private int paddingB = 0;
private int mScrollX = 0;
private float baseLineHeight;
private Paint paint1;
private boolean isDark = false;
public HourlyForecastView(Context context) {
this(context, null);
}
public HourlyForecastView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public HourlyForecastView(final Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public HourlyForecastView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
mContext = context;
// if (ContentUtil.APP_SETTING_THEME.equals(“深色”)) {
// isDark = true;
// } else {
// isDark = false;
// }
isDark = false;
initDefValue();
initPaint();
}
private static int ITEM_SIZE = 24;
public void initData(List<HourlyResponse.HourlyBean> weatherData) {
hourlyWeatherList = weatherData;
int size = weatherData.size();
ITEM_SIZE = size;
dashLineList = new ArrayList<>();
Iterator iterator = weatherData.iterator();
HourlyResponse.HourlyBean hourlyBase;
String lastText = “”;
int idx = 0;
while (iterator.hasNext()) {
hourlyBase = (HourlyResponse.HourlyBean) iterator.next();
if (!hourlyBase.getIcon().equals(lastText)) {
if (idx != size - 1) {
dashLineList.add(idx);//从0开始添加虚线位置的索引值idx
lastText = hourlyBase.getIcon();
}
}
idx++;
}
dashLineList.add(size - 1);//添加最后一条虚线位置的索引值idx
invalidate();
}
private void initDefValue() {
DisplayMetrics dm = getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
itemWidth = DisplayUtil.dp2px(mContext, 30);
defWidthPixel = itemWidth * (ITEM_SIZE - 1);
defHeightPixel = DisplayUtil.dp2px(mContext, 80);
lowestTempHeight = DisplayUtil.dp2px(mContext, 40);//长度 非y轴值
highestTempHeight = DisplayUtil.dp2px(mContext, 70);
//defPadding
paddingT = DisplayUtil.dp2px(mContext, 20);
paddingL = DisplayUtil.dp2px(mContext, 10);
paddingR = DisplayUtil.dp2px(mContext, 15);
textSize = DisplayUtil.sp2px(mContext, 12);
bitmapHeight = 1 / 2f * (2 * defHeightPixel - lowestTempHeight) + DisplayUtil.dp2px(mContext, 2);//- 给文字留地方
bitmapXY = 18;
}
private TextPaint textLinePaint;
private void initPaint() {
// setLayerType(View.LAYER_TYPE_SOFTWARE, null);//关闭硬件加速
paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1.setColor(mContext.getResources().getColor(R.color.line_back_dark));
paint1.setStyle(Paint.Style.FILL);
foldLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
foldLinePaint.setStyle(Paint.Style.STROKE);
foldLinePaint.setStrokeWidth(5);
//折线颜色
foldLinePaint.setColor(mContext.getResources().getColor(R.color.line_color_2));
backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
backPaint.setStrokeWidth(2);
backPaint.setAntiAlias(true);
dashPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dashPaint.setColor(mContext.getResources().getColor(R.color.back_white));
DashPathEffect pathEffect = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
dashPaint.setPathEffect(pathEffect);
dashPaint.setStrokeWidth(3);
dashPaint.setAntiAlias(true);
dashPaint.setStyle(Paint.Style.STROKE);
textPaint = new Paint();
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(textSize);
textLinePaint = new TextPaint();
textLinePaint.setTextSize(DisplayUtil.sp2px(getContext(), 12));
textLinePaint.setAntiAlias(true);
textLinePaint.setColor(mContext.getResources().getColor(R.color.black));
//底部时间文字颜色
textPaint.setColor(mContext.getResources().getColor(R.color.search_light_un_color));
baseLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
baseLinePaint.setStrokeWidth(3);
baseLinePaint.setStyle(Paint.Style.STROKE);
baseLinePaint.setColor(mContext.getResources().getColor(R.color.slategray));
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setFilterBitmap(true);//图像滤波处理
bitmapPaint.setDither(true);//防抖动
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//当设置的padding值小于默认值是设置为默认值
paddingT = DisplayUtil.dp2px(mContext, 20);
paddingL = DisplayUtil.dp2px(mContext, 10);
paddingR = DisplayUtil.dp2px(mContext, 15);
paddingB = Math.max(paddingB, getPaddingBottom());
//获取测量模式
//注意 HorizontalScrollView的子View 在没有明确指定dp值的情况下 widthMode总是MeasureSpec.UNSPECIFIED
//同理 ScrollView的子View的heightMode
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取测量大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
mWidth = widthSize + paddingL + paddingR;
mHeight = heightSize;
}
//如果为wrap_content 那么View大小为默认值
if (widthMode == MeasureSpec.UNSPECIFIED && heightMode == MeasureSpec.AT_MOST) {
mWidth = defWidthPixel + paddingL + paddingR;
mHeight = defHeightPixel + paddingT + paddingB;
}
//设置视图的大小
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
initDefValue();
initPaint();
if (hourlyWeatherList != null && hourlyWeatherList.size() != 0) {
drawLines(canvas);
drawBitmaps(canvas);
drawTemp(canvas);
}
}
private void drawTemp(Canvas canvas) {
for (int i = 0; i < hourlyWeatherList.size(); i++) {
if (currentItemIndex == i) {
//计算提示文字的运动轨迹
// int Y = getTempBarY(i);
String tmp = hourlyWeatherList.get(i).getTemp();
float temp = Integer.parseInt(tmp);
int Y = (int) (tempHeightPixel(temp) + paddingT);
//画出温度提示
int offset = itemWidth / 4;
Rect targetRect = new Rect(getScrollBarX(), Y - DisplayUtil.dip2px(getContext(), 24)
, getScrollBarX() + offset, Y - DisplayUtil.dip2px(getContext(), 4));
Paint.FontMetricsInt fontMetrics = textLinePaint.getFontMetricsInt();
int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
textLinePaint.setTextAlign(Paint.Align.LEFT);
// if (ContentUtil.APP_SETTING_UNIT.equals(“hua”)) {
// tmp = String.valueOf(TransUnitUtil.getF(tmp));
// }
canvas.drawText(tmp + “°”, targetRect.centerX(), baseline, textLinePaint);
}
}
}
private void drawBitmaps(Canvas canvas) {
int scrollX = mScrollX;
boolean leftHide;
boolean rightHide;
for (int i = 0; i < dashLineList.size() - 1; i++) {
leftHide = true;
rightHide = true;
int left = itemWidth * dashLineList.get(i) + paddingL;
int right = itemWidth * dashLineList.get(i + 1) + paddingL;
//图的中间位置 drawBitmap是左边开始画
float drawPoint = 0;
if (left > scrollX && left < scrollX + screenWidth) {
leftHide = false;//左边缘显示
}
if (right > scrollX && right < scrollX + screenWidth) {
rightHide = false;
}
if (!leftHide && !rightHide) {//左右边缘都显示
drawPoint = (left + right) / 2f;
} else if (leftHide && !rightHide) {//右边缘与屏幕左边
drawPoint = (scrollX + right) / 2f;
} else if (!leftHide) {//左边缘与屏幕右边
//rightHide is True when reach this statement
drawPoint = (left + screenWidth + scrollX) / 2f;
} else {//左右边缘都不显示
if (right < scrollX + screenWidth) { //左右边缘都在屏幕左边
continue;
} else if (left > scrollX + screenWidth) {//左右边缘都在屏幕右边
continue;
} else {
drawPoint = (screenWidth) / 2f + scrollX;
}
}
String code = hourlyWeatherList.get(dashLineList.get(i)).getIcon();
BitmapDrawable bd;
if (code.contains(“d”)) {
bd = (BitmapDrawable) mContext.getResources().getDrawable(IconUtils.getDayIconDark(code.replace(“d”, “”)));
} else {
bd = (BitmapDrawable) mContext.getResources().getDrawable(IconUtils.getNightIconDark(code.replace(“n”, “”)));
}
assert bd != null;
Bitmap bitmap = DisplayUtil.bitmapResize(bd.getBitmap(),
DisplayUtil.dp2px(mContext, bitmapXY), DisplayUtil.dp2px(mContext, bitmapXY));
//越界判断
if (drawPoint >= right - bitmap.getWidth() / 2f) {
drawPoint = right - bitmap.getWidth() / 2f;
}
if (drawPoint <= left + bitmap.getWidth() / 2f) {
drawPoint = left + bitmap.getWidth() / 2f;
}
drawBitmap(canvas, bitmap, drawPoint, bitmapHeight);
// String text = hourlyWeatherList.get(dashLineList.get(i)).getCond_txt();
// textPaint.setTextSize(DisplayUtil.sp2px(mContext, 8));
// canvas.drawText(text, drawPoint, bitmapHeight + bitmap.getHeight() + 100 / 3f, textPaint);
}
}
private void drawBitmap(Canvas canvas, Bitmap bitmap, float left, float top) {
canvas.save();
canvas.drawBitmap(bitmap, left - bitmap.getWidth() / 2, top, bitmapPaint);
canvas.restore();
}
private void drawLines(Canvas canvas) {
//底部的线的高度 高度为控件高度减去text高度的1.5倍
baseLineHeight = mHeight - 1.5f * textSize;
Path path = new Path();
List dashWidth = new ArrayList<>();
List dashHeight = new ArrayList<>();
List mPointList = new ArrayList<>();
for (int i = 0; i < hourlyWeatherList.size(); i++) {
float temp = Integer.parseInt(hourlyWeatherList.get(i).getTemp());
float w = itemWidth * i + paddingL;
float h = tempHeightPixel(temp) + paddingT;
Point point = new Point((int) w, (int) h);
mPointList.add(point);
//画虚线
if (dashLineList.contains(i)) {
dashWidth.add(w);
dashHeight.add(h);
}
}
float prePreviousPointX = Float.NaN;
float prePreviousPointY = Float.NaN;
float previousPointX = Float.NaN;
float previousPointY = Float.NaN;
float currentPointX = Float.NaN;
float currentPointY = Float.NaN;
float nextPointX;
float nextPointY;
for (int valueIndex = 0; valueIndex < hourlyWeatherList.size(); ++valueIndex) {
if (Float.isNaN(currentPointX)) {
Point point = mPointList.get(valueIndex);
currentPointX = point.x;
currentPointY = point.y;
}
if (Float.isNaN(previousPointX)) {
//是否是第一个点
if (valueIndex > 0) {
Point point = mPointList.get(valueIndex - 1);
previousPointX = point.x;
previousPointY = point.y;
} else {
//是的话就用当前点表示上一个点
previousPointX = currentPointX;
previousPointY = currentPointY;
}
}
if (Float.isNaN(prePreviousPointX)) {
//是否是前两个点
if (valueIndex > 1) {
Point point = mPointList.get(valueIndex - 2);
prePreviousPointX = point.x;
prePreviousPointY = point.y;
} else {
//是的话就用当前点表示上上个点
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
}
}
// 判断是不是最后一个点了
if (valueIndex < hourlyWeatherList.size() - 1) {
Point point = mPointList.get(valueIndex + 1);
nextPointX = point.x;
nextPointY = point.y;
} else {
//是的话就用当前点表示下一个点
nextPointX = currentPointX;
nextPointY = currentPointY;
}
if (valueIndex == 0) {
// 将Path移动到开始点
path.moveTo(currentPointX, currentPointY);
} else {
// 求出控制点坐标
final float firstDiffX = (currentPointX - prePreviousPointX);
final float firstDiffY = (currentPointY - prePreviousPointY);
final float secondDiffX = (nextPointX - previousPointX);
final float secondDiffY = (nextPointY - previousPointY);
final float firstControlPointX = previousPointX + (0.2F * firstDiffX);
final float firstControlPointY = previousPointY + (0.2F * firstDiffY);
final float secondControlPointX = currentPointX - (0.2F * secondDiffX);
final float secondControlPointY = currentPointY - (0.2F * secondDiffY);
//画出曲线
path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
currentPointX, currentPointY);
}
// 更新值,
prePreviousPointX = previousPointX;
prePreviousPointY = previousPointY;
previousPointX = currentPointX;
previousPointY = currentPointY;
currentPointX = nextPointX;
currentPointY = nextPointY;
}
//画折线
canvas.drawPath(path, foldLinePaint);
path.lineTo(mWidth - paddingR, baseLineHeight);
path.lineTo(paddingL, baseLineHeight);
//画阴影
int[] shadeColors = new int[]{
Color.argb(100, 60, 174, 242),
Color.argb(30, 60, 174, 242),
Color.argb(18, 237, 238, 240)};
Shader mShader = new LinearGradient(0, 0, 0, getHeight(), shadeColors, null, Shader.TileMode.CLAMP);
backPaint.setShader(mShader);
canvas.drawPath(path, backPaint);
//画虚线
drawDashLine(dashWidth, dashHeight, canvas);
for (int i = 0; i < hourlyWeatherList.size(); i++) {
float temp = Integer.parseInt(hourlyWeatherList.get(i).getTemp());
float w = itemWidth * i + paddingL;
float h = tempHeightPixel(temp) + paddingT;
//画时间
String time = hourlyWeatherList.get(i).getFxTime();
//画时间
if (ITEM_SIZE > 8) {
if (i % 2 == 0) {
if (i == 0) {
textPaint.setTextAlign(Paint.Align.LEFT);
} else {
textPaint.setTextAlign(Paint.Align.CENTER);
}
canvas.drawText(time.substring(time.length() - 11, time.length() - 6), w, baseLineHeight + textSize + DisplayUtil.dip2px(mContext, 3), textPaint);
}
} else {
textPaint.setTextAlign(Paint.Align.CENTER);
if (i == 0) {
canvas.drawText(“. 现在”, w, baseLineHeight + textSize + DisplayUtil.dip2px(mContext, 3), textPaint);
} else {
canvas.drawText(time.substring(time.length() - 11, time.length() - 6), w, baseLineHeight + textSize + DisplayUtil.dip2px(mContext, 3), textPaint);
}
}
}
}
//画虚线
private void drawDashLine(List dashWidth, List dashHeight, Canvas canvas) {
if (dashHeight != null && dashHeight.size() > 1) {
for (int i = 1; i < dashHeight.size() - 1; i++) {
canvas.drawLine(dashWidth.get(i), dashHeight.get(i) + 3, dashWidth.get(i), baseLineHeight, dashPaint);
}
}
}
public float tempHeightPixel(float tmp) {
float res = ((tmp - lowestTemp) / (highestTemp - lowestTemp)) * (highestTempHeight - lowestTempHeight) + lowestTempHeight;
return defHeightPixel - res;//y从上到下
}
@Override
public void update(int scrollX) {
mScrollX = scrollX;
}
public void setLowestTemp(int lowestTemp) {
this.lowestTemp = lowestTemp;
}
public void setHighestTemp(int highestTemp) {
this.highestTemp = highestTemp;
}
private int maxScrollOffset = 0;//滚动条最长滚动距离
private int scrollOffset = 0; //滚动条偏移量
private int currentItemIndex = 0; //当前滚动的位置所对应的item下标
//设置scrollerView的滚动条的位置,通过位置计算当前的时段
public void setScrollOffset(int offset, int maxScrollOffset) {
this.maxScrollOffset = maxScrollOffset + DisplayUtil.dp2px(mContext, 50);
scrollOffset = offset;
currentItemIndex = calculateItemIndex();
invalidate();
}
//通过滚动条偏移量计算当前选择的时刻
private int calculateItemIndex() {
int x = getScrollBarX();
int sum = paddingL - itemWidth / 2;
for (int i = 0; i < ITEM_SIZE - 1; i++) {
sum += itemWidth;
if (x < sum)
return i;
}
return ITEM_SIZE - 1;
}
private int getScrollBarX() {
int x = (ITEM_SIZE - 1) * itemWidth * scrollOffset / maxScrollOffset;
x = x - DisplayUtil.dp2px(mContext, 3);
return x;
}
}
IndexHorizontalScrollView.java
package com.llw.goodweather.view.horizonview;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.HorizontalScrollView;
import com.llw.goodweather.utils.DisplayUtil;
/**
- 横向滑动条
*/
public class IndexHorizontalScrollView extends HorizontalScrollView {
private HourlyForecastView hourlyForecastView;
public IndexHorizontalScrollView(Context context) {
this(context, null);
}
public IndexHorizontalScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IndexHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
-
绘制
-
@param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int offset = computeHorizontalScrollOffset();
int maxOffset = computeHorizontalScrollRange() - DisplayUtil.getScreenWidth(getContext());
if(hourlyForecastView != null){
hourlyForecastView.setScrollOffset(offset, maxOffset);
}
}
/**
-
设置24小时的View
-
@param today24HourView
*/
public void setToday24HourView(HourlyForecastView today24HourView){
this.hourlyForecastView = today24HourView;
}
}
里面还有一些颜色值,在mvplibrary下的colors.xml,如下
<?xml version="1.0" encoding="utf-8"?>#C6D7F4
#FBFEF7
#ffffff
#000000
#1E1E1A
#77d034
#9FC8E9
#00000000
#22000000
#22FFFFFF
#F38A50
#FFEFD5
#454545
#BABABA
#FFBCB3
#FDEBE8
#E7F3FC
#F2F2F2
#707070
#6D6D6D
#FF0A00
#E3E5E8
#E7C373
#243440
#C8DCFF
#F8F8F8
#44000000
#66000000
#70000000
#88000000
#FF7E45
#B3BCCA
#22FFFFFF
#44FFFFFF
#66FFFFFF
#88FFFFFF
#56004f
#F6F6F6
#626262
#141414
#DEDEE1
#D9D9D9
#818181
#f7f8fa
#E9EAEF
#B9C0CA
#3f8DA0BA
#919191
#666666
#708090
#50A0FF
#002C46
#597EF7
#33F2BE55
#33446FF2
#33AD9442
#334A5CC4
#A4A4A4
#3C91F2
#595959
然后在activity_map_weather.xml中
这一部分布局代码如下:
<TextView
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_margin=“@dimen/dp_12”
android:text=“24小时预报”
android:textColor=“@color/black_4”
android:textSize=“@dimen/sp_16” />
<RelativeLayout
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_marginBottom=“@dimen/dp_12”>
<TextView
android:id=“@+id/tv_line_max_tmp”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_marginLeft=“@dimen/dp_12”
android:layout_marginTop=“@dimen/dp_16”
android:text=“21°”
android:textColor=“@color/black_4”
android:textSize=“@dimen/sp_16” />
<TextView
android:id=“@+id/tv_line_min_tmp”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_marginLeft=“@dimen/dp_12”
android:layout_marginTop=“@dimen/dp_66”
android:text=“11°”
android:textColor=“@color/black_4”
android:textSize=“@dimen/dp_16” />
<LinearLayout
android:layout_width=“match_parent”
android:layout_height=“@dimen/dp_98”
android:layout_marginLeft=“@dimen/dp_40”
android:orientation=“horizontal”
android:paddingRight=“@dimen/dp_12”>
<com.llw.goodweather.view.horizonview.IndexHorizontalScrollView
android:id=“@+id/hsv”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”>
<com.llw.goodweather.view.horizonview.HourlyForecastView
android:id=“@+id/hourly”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content” />
</com.llw.goodweather.view.horizonview.IndexHorizontalScrollView>
然后在MapWeatherActivity中
@BindView(R.id.tv_line_max_tmp)
TextView tvLineMaxTmp;//今日最高温
@BindView(R.id.tv_line_min_tmp)
TextView tvLineMinTmp;//今日最低温
@BindView(R.id.hourly)
HourlyForecastView hourly;//和风自定义逐小时天气渲染控件
@BindView(R.id.hsv)
IndexHorizontalScrollView hsv;//和风自定义滚动条
在搜索城市的返回中,新增一个24小时天气预报请求
然后在请求返回中做处理
然后实现里面的一个构造方法
/**
-
24小时天气预报数据返回
-
@param response
*/
@Override
public void getWeatherHourlyResult(Response response) {
if(response.body().getCode().equals(Constant.SUCCESS_CODE)){
List<HourlyResponse.HourlyBean> hourlyWeatherList = response.body().getHourly();
List<HourlyResponse.HourlyBean> data = new ArrayList<>();
if (hourlyWeatherList.size() > 23) {
for (int i = 0; i < 24; i++) {
data.add(hourlyWeatherList.get(i));
String condCode = data.get(i).getIcon();
String time = data.get(i).getFxTime();
time = time.substring(time.length() - 11, time.length() - 9);
int hourNow = Integer.parseInt(time);
if (hourNow >= 6 && hourNow <= 19) {
data.get(i).setIcon(condCode + “d”);
} else {
data.get(i).setIcon(condCode + “n”);
}
}
} else {
for (int i = 0; i < hourlyWeatherList.size(); i++) {
data.add(hourlyWeatherList.get(i));
String condCode = data.get(i).getIcon();
String time = data.get(i).getFxTime();
time = time.substring(time.length() - 11, time.length() - 9);
int hourNow = Integer.parseInt(time);
if (hourNow >= 6 && hourNow <= 19) {
data.get(i).setIcon(condCode + “d”);
} else {
data.get(i).setIcon(condCode + “n”);
}
}
}
int minTmp = Integer.parseInt(data.get(0).getTemp());
int maxTmp = minTmp;
for (int i = 0; i < data.size(); i++) {
int tmp = Integer.parseInt(data.get(i).getTemp());
minTmp = Math.min(tmp, minTmp);
maxTmp = Math.max(tmp, maxTmp);
}
//设置当天的最高最低温度
hourly.setHighestTemp(maxTmp);
hourly.setLowestTemp(minTmp);
if (maxTmp == minTmp) {
hourly.setLowestTemp(minTmp - 1);
}
hourly.initData(data);
tvLineMaxTmp.setText(maxTmp + “°”);
tvLineMinTmp.setText(minTmp + “°”);
}else {
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode()));
}
}
OK,然后运行一下:
首先定义样式,在styles.xml中增加
然后在view包下新增一个
SunView.java
package com.llw.goodweather.view.skyview;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import com.llw.goodweather.R;
import com.llw.goodweather.utils.DisplayUtil;
import java.text.DecimalFormat;
/**
- 太阳、月亮自定义View
*/
public class SunView extends View {
private int mWidth; //屏幕宽度
private int marginTop = 50;//离顶部的高度
private int mCircleColor; //圆弧颜色
private int mFontColor; //字体颜色
private int mRadius; //圆的半径
private float mCurrentAngle; //当前旋转的角度
private float mTotalMinute; //总时间(日落时间减去日出时间的总分钟数)
private float mNeedMinute; //当前时间减去日出时间后的总分钟数
private float mPercentage; //根据所给的时间算出来的百分占比
private float positionX, positionY; //太阳图片的x、y坐标
private float mFontSize; //字体大小
private String mStartTime; //开始时间(日出时间)
private String mEndTime; //结束时间(日落时间)
private String mCurrentTime; //当前时间
private Paint mTextPaint; //画笔
private Paint mLinePaint; //画笔
private Paint mTimePaint; //画笔
private RectF mRectF; //半圆弧所在的矩形
private Bitmap mSunIcon; //太阳图片
private WindowManager wm;
private Paint mShadePaint;
private Paint mPathPaint;
private Context mContext;
private boolean isSun = true;
private float endHour;
private Paint shadePaint;
private Paint pathPaint;
public SunView(Context context) {
this(context, null);
}
public SunView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SunView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, @Nullable AttributeSet attrs) {
mContext = context;
marginTop = DisplayUtil.dip2px(context, 30);
@SuppressLint(“CustomViewStyleable”) TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.SunAnimationView);
mCircleColor = type.getColor(R.styleable.SunAnimationView_sun_circle_color, getContext().getResources().getColor(R.color.dark_text_color));
mFontColor = type.getColor(R.styleable.SunAnimationView_sun_font_color, getContext().getResources().getColor(R.color.colorAccent));
mRadius = type.getInteger(R.styleable.SunAnimationView_sun_circle_radius, DisplayUtil.dp2px(getContext(), 130));
mRadius = DisplayUtil.dp2px(getContext(), mRadius);
mFontSize = type.getDimension(R.styleable.SunAnimationView_sun_font_size, DisplayUtil.dp2px(getContext(), 10));
mFontSize = DisplayUtil.dp2px(getContext(), mFontSize);
isSun = type.getBoolean(R.styleable.SunAnimationView_type, true);
type.recycle();
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTimePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
shadePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
public void setType(boolean isSun, int circleColor, int fontColor) {
this.isSun = isSun;
mCircleColor = circleColor;
mFontColor = fontColor;
}
public void setTimes(String startTime, String endTime, String currentTime) {
mStartTime = startTime;
mEndTime = endTime;
mCurrentTime = currentTime;
String currentTimes[] = currentTime.split(“:”);
String startTimes[] = startTime.split(“:”);
String endTimes[] = endTime.split(“:”);
float currentHour = Float.parseFloat(currentTimes[0]);
float currentMinute = Float.parseFloat(currentTimes[1]);
float startHour = Float.parseFloat(startTimes[0]);
endHour = Float.parseFloat(endTimes[0]);
if (!isSun && endHour < startHour) {
endHour += 24;
}
float endMinute = Float.parseFloat(endTimes[1]);
if (isSun) {
if (currentHour > endHour) {
mCurrentTime = endTime;
} else if (currentHour == endHour && currentMinute >= endMinute) {
mCurrentTime = endTime;
}
}
mTotalMinute = calculateTime(mStartTime, mEndTime, false);//计算总时间,单位:分钟
mNeedMinute = calculateTime(mStartTime, mCurrentTime, true);//计算当前所给的时间 单位:分钟
mPercentage = Float.parseFloat(formatTime(mTotalMinute, mNeedMinute));//当前时间的总分钟数占日出日落总分钟数的百分比
mCurrentAngle = 180 * mPercentage;
setAnimation(0, mCurrentAngle, 2000);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
mWidth = wm.getDefaultDisplay().getWidth() / 2;
positionX = mWidth / 2 - mRadius - DisplayUtil.dip2px(mContext, 9); // 太阳图片的初始x坐标
positionY = mRadius; // 太阳图片的初始y坐标
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, mWidth / 2 - mRadius, marginTop, mWidth / 2 + mRadius, mRadius * 2 + marginTop);
}
@SuppressLint(“DrawAllocation”)
@Override
protected void onDraw(Canvas canvas) {
// 渐变遮罩的画笔
shadePaint.setColor(mContext.getResources().getColor(R.color.back_white));
shadePaint.setStyle(Paint.Style.FILL);
mShadePaint = shadePaint;
pathPaint.setColor(mContext.getResources().getColor(R.color.attention_text_light));
if (isSun) {
mSunIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_sun);
} else {
mSunIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_moon);
}
mSunIcon = DisplayUtil.bitmapResize(mSunIcon, DisplayUtil.dp2px(mContext, 18), DisplayUtil.dp2px(mContext, 18));
pathPaint.setStyle(Paint.Style.STROKE);
pathPaint.setStrokeWidth(2);
mPathPaint = pathPaint;
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setDither(true);//防止抖动
mLinePaint.setStrokeWidth(2);
//第一步:画半圆
drawSemicircle(canvas);
canvas.save();
mLinePaint.setColor(mContext.getResources().getColor(R.color.attention_text_light));
canvas.drawLine(mWidth / 2 - mRadius - DisplayUtil.dip2px(mContext, 10), mRadius + marginTop, mWidth / 2 + mRadius + DisplayUtil.dip2px(mContext, 10), mRadius + marginTop, mLinePaint);
//第二步:绘制太阳的初始位置 以及 后面在动画中不断的更新太阳的X,Y坐标来改变太阳图片在视图中的显示
//第三部:绘制图上的文字
drawSunPosition(canvas);
drawFont(canvas);
super.onDraw(canvas);
}
/**
- 绘制半圆
*/
private void drawSemicircle(Canvas canvas) {
mRectF = new RectF(mWidth / 2 - mRadius, marginTop, mWidth / 2 + mRadius, mRadius * 2 + marginTop);
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setDither(true);//防止抖动
mTextPaint.setColor(mCircleColor);
canvas.drawArc(mRectF, 180, 180, true, mTextPaint);
}
/**
- 绘制太阳的位置
*/
private void drawSunPosition(Canvas canvas) {
// canvas.drawRect(positionX + DisplayUtil.dp2px(mContext, 10), marginTop, mWidth / 2 + mRadius, mRadius * 2 + marginTop, mShadePaint);
canvas.drawArc(mRectF, 180, 180, true, mPathPaint);
canvas.drawBitmap(mSunIcon, positionX, positionY, mLinePaint);
}
/**
-
绘制底部左右边的日出时间和日落时间
-
@param canvas
*/
private void drawFont(Canvas canvas) {
mFontSize = DisplayUtil.dp2px(getContext(), 12);
mTextPaint.setColor(mFontColor);
mTextPaint.setTextSize(mFontSize);
mTimePaint.setColor(getResources().getColor(R.color.black_4));
mTimePaint.setTextSize(mFontSize);
String startTime = TextUtils.isEmpty(mStartTime) ? “” : mStartTime;
String endTime = TextUtils.isEmpty(mEndTime) ? “” : mEndTime;
String sunrise = “日出”;
String sunset = “日落”;
if (!isSun) {
sunrise = “月出”;
sunset = “月落”;
}
mTimePaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(sunrise, mWidth / 2 - mRadius + DisplayUtil.dip2px(mContext, 8), mRadius + DisplayUtil.dip2px(mContext, 16) + marginTop, mTextPaint);
canvas.drawText(startTime, mWidth / 2 - mRadius + DisplayUtil.dip2px(mContext, 8), mRadius + DisplayUtil.dip2px(mContext, 32) + marginTop, mTimePaint);
canvas.drawText(sunset, mWidth / 2 + mRadius - DisplayUtil.dip2px(mContext, 8), mRadius + DisplayUtil.dip2px(mContext, 16) + marginTop, mTextPaint);
canvas.drawText(endTime, mWidth / 2 + mRadius - DisplayUtil.dip2px(mContext, 8), mRadius + DisplayUtil.dip2px(mContext, 32) + marginTop, mTimePaint);
}
/**
-
精确计算文字宽度
-
@param paint 画笔
-
@param str 字符串文本
*/
public static int getTextWidth(Paint paint, String str) {
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
paint.getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
return iRet;
}
/**
-
根据日出和日落时间计算出一天总共的时间:单位为分钟
-
@param startTime 日出时间
-
@param endTime 日落时间
-
@return
*/
private float calculateTime(String startTime, String endTime, boolean isCurrent) {
String startTimes[] = startTime.split(“:”);
String endTimes[] = endTime.split(“:”);
float startHour = Float.parseFloat(startTimes[0]);
float startMinute = Float.parseFloat(startTimes[1]);
float endHour = Float.parseFloat(endTimes[0]);
float endMinute = Float.parseFloat(endTimes[1]);
if (!isCurrent && !isSun && endHour < startHour) {
endHour += 24;
}
if (isSun) {
if (startHour > endHour) {
return 0;
} else if (startHour == endHour && startMinute >= endMinute) {
return 0;
}
} else {
if (isCurrent) {
if (startHour > endHour) {
return 0;
} else if (startHour == endHour && startMinute >= endMinute) {
return 0;
}
} else {
if (startHour >= endHour + 24) {
return 0;
}
}
}
if (checkTime(startTime, endTime)) {
return (endHour - startHour - 1) * 60 + (60 - startMinute) + endMinute;
}
return 0;
}
/**
-
对所给的时间做一下简单的数据校验
-
@param startTime
-
@param endTime
-
@return
*/
private boolean checkTime(String startTime, String endTime) {
if (TextUtils.isEmpty(startTime) || TextUtils.isEmpty(endTime)
|| !startTime.contains(“:”) || !endTime.contains(“:”)) {
return false;
}
String startTimes[] = startTime.split(“:”);
String endTimes[] = endTime.split(“:”);
float startHour = Float.parseFloat(startTimes[0]);
float startMinute = Float.parseFloat(startTimes[1]);
float endHour = Float.parseFloat(endTimes[0]);
float endMinute = Float.parseFloat(endTimes[1]);
//如果所给的时间(hour)小于日出时间(hour)或者大于日落时间(hour)
if ((startHour < Float.parseFloat(mStartTime.split(“:”)[0]))
|| (endHour > this.endHour)) {
return false;
}
//如果所给时间与日出时间:hour相等,minute小于日出时间
if ((startHour == Float.parseFloat(mStartTime.split(“:”)[0]))
&& (startMinute < Float.parseFloat(mStartTime.split(“:”)[1]))) {
return false;
}
//如果所给时间与日落时间:hour相等,minute大于日落时间
if ((startHour == this.endHour)
&& (endMinute > Float.parseFloat(mEndTime.split(“:”)[1]))) {
return false;
}
if (startHour < 0 || endHour < 0
|| startHour > 23 || endHour > 23
|| startMinute < 0 || endMinute < 0
|| startMinute > 60 || endMinute > 60) {
return false;
}
return true;
}
/**
-
根据具体的时间、日出日落的时间差值 计算出所给时间的百分占比
-
@param totalTime 日出日落的总时间差
-
@param needTime 当前时间与日出时间差
-
@return
*/
private String formatTime(float totalTime, float needTime) {
if (totalTime == 0)
return “0.00”;
DecimalFormat decimalFormat = new DecimalFormat(“0.00”);//保留2位小数,构造方法的字符格式这里如果小数不足2位,会以0补足.
return decimalFormat.format(needTime / totalTime);//format 返回的是字符串
}
private void setAnimation(float startAngle, float currentAngle, int duration) {
ValueAnimator sunAnimator = ValueAnimator.ofFloat(startAngle, currentAngle);
sunAnimator.setDuration(duration);
sunAnimator.setTarget(currentAngle);
sunAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//每次要绘制的圆弧角度
mCurrentAngle = (float) animation.getAnimatedValue();
invalidateView();
}
});
sunAnimator.start();
}
private void invalidateView() {
//绘制太阳的x坐标和y坐标
positionX = mWidth / 2 - (float) (mRadius * Math.cos((mCurrentAngle) * Math.PI / 180)) - DisplayUtil.dp2px(mContext, 10);
positionY = mRadius - (float) (mRadius * Math.sin((mCurrentAngle) * Math.PI / 180)) + DisplayUtil.dip2px(mContext, 18);
invalidate();
}
}
然后进入到activity_map_weather.xml
<LinearLayout
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:gravity=“center_vertical”
android:orientation=“horizontal”>
<TextView
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_margin=“@dimen/dp_12”
android:text=“太阳和月亮”
android:textColor=“@color/black_4”
android:textSize=“@dimen/sp_16” />
<TextView
android:id=“@+id/tv_moon_state”
android:layout_width=“@dimen/dp_0”
android:layout_height=“wrap_content”
android:layout_weight=“1”
android:gravity=“right”
android:paddingRight=“@dimen/dp_12”
android:textColor=“@color/moon_tv_color”
android:textSize=“@dimen/sp_14” />
<LinearLayout
android:layout_width=“match_parent”
android:layout_height=“@dimen/dp_160”
android:layout_marginTop=“@dimen/dp_24”
android:orientation=“horizontal”>
<com.llw.goodweather.view.skyview.SunView
android:id=“@+id/sun_view”
android:layout_width=“0dp”
android:layout_height=“@dimen/dp_240”
android:layout_weight=“1”
app:sun_circle_color=“@color/sun_light_circle”
app:sun_circle_radius=“70”
app:sun_font_color=“@color/color_a4a4a4”
app:sun_font_size=“12px” />
<com.llw.goodweather.view.skyview.SunView
android:id=“@+id/moon_view”
android:layout_width=“0dp”
android:layout_height=“@dimen/dp_240”
android:layout_weight=“1”
app:sun_circle_color=“@color/moon_light_circle”
app:sun_circle_radius=“70”
app:sun_font_color=“@color/color_a4a4a4”
app:sun_font_size=“12px”
app:type=“false” />
然后进入到MapWeatherActivity
@BindView(R.id.sun_view)
SunView sunView;//太阳
@BindView(R.id.moon_view)
SunView moonView;//月亮
@BindView(R.id.tv_moon_state)
TextView tvMoonState;//月亮状态
然后就要新增接口了,在新增接口之前,有一个小插曲就是,如果你是在S6版本下创建的Key,那么你是访问不了V7版本下的太阳和月亮的接口的,会提示403,就是没有权限,所以需要你重新创建一个应用KEY,这是我自己新建的KEY,你最好也自己新建一个
打开Constant,新增如下:
再打开ApiService,新增并且修改之前的接口,这里我就不一一展示了
/**
- 太阳和月亮 日出日落、月升月落
*/
@GET(“/v7/astronomy/sunmoon?key=”+ API_KEY)
Call getSunMoon(@Query(“location”) String location, @Query(“date”) String date);
SunMoonResponse的代码如下:
package com.llw.goodweather.bean;
import java.util.List;
/**
- 太阳和月亮数据实体
*/
public class SunMoonResponse {
/**
-
code : 200
-
updateTime : 2020-09-02T18:00+08:00
-
fxLink : http://hfx.link/2ax1
-
sunrise : 2020-09-02T05:44+08:00
-
sunset : 2020-09-02T18:41+08:00
-
moonrise : 2020-09-02T19:10+08:00
-
moonset : 2020-09-03T05:19+08:00
-
moonPhase : [{“fxTime”:“2020-09-02T00:00+08:00”,“value”:“0.48”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T01:00+08:00”,“value”:“0.48”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T02:00+08:00”,“value”:“0.48”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T03:00+08:00”,“value”:“0.48”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T04:00+08:00”,“value”:“0.48”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T05:00+08:00”,“value”:“0.49”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T06:00+08:00”,“value”:“0.49”,“name”:“盈凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T07:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T08:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T09:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T10:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T11:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T12:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T13:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T14:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T15:00+08:00”,“value”:“0.51”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T16:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T17:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T18:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T19:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T20:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T21:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T22:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”},{“fxTime”:“2020-09-02T23:00+08:00”,“value”:“0.52”,“name”:“亏凸月”,“illumination”:“100”}]
-
refer : {“sources”:[“heweather.com”],“license”:[“no commercial use”]}
*/
private String code;
private String updateTime;
private String fxLink;
private String sunrise;
private String sunset;
private String moonrise;
private String moonset;
private ReferBean refer;
private List moonPhase;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getFxLink() {
return fxLink;
}
public void setFxLink(String fxLink) {
this.fxLink = fxLink;
}
public String getSunrise() {
return sunrise;
}
public void setSunrise(String sunrise) {
this.sunrise = sunrise;
}
public String getSunset() {
return sunset;
}
public void setSunset(String sunset) {
this.sunset = sunset;
}
public String getMoonrise() {
return moonrise;
}
public void setMoonrise(String moonrise) {
this.moonrise = moonrise;
}
public String getMoonset() {
return moonset;
}
public void setMoonset(String moonset) {
this.moonset = moonset;
}
public ReferBean getRefer() {
return refer;
}
public void setRefer(ReferBean refer) {
this.refer = refer;
}
原文地址:https://blog.csdn.net/2401_89790750/article/details/145257881
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!