上一篇:Android 天气APP(二十四)地图天气(上)自动定位和地图点击定位 上篇文章中,完成了对地图的控制,那么这篇文章中完成对天气数据的渲染。
完成这篇文章实现的效果如下,如果你觉得不行那就可以不用看下面了。
文章目录
一、嵌套布局
在上一篇文章中,实现地图的功能,只用了一个地图控件和一个浮动按钮。而在这一篇文章中,为了提高页面的可用性和用户交互的效果,我用了CoordinatorLayout,这是一个嵌套滑动布局。
接下来来看看详细的布局内容:
然后来看这个里面放了什么
这里我放了一个相对布局,这是用于控制滑动的布局 在页面的底部留有一部分布局,可以通过向上拖动到屏幕的底部,不过为了更好地效果,我在CoordinatorLayout中设置50的上边距。
然后再看这个相对布局里面是什么内容
展开之后里面是NestedScrollView和LinearLayout,
BottomSheetBehavior上滑 展开后主要滑动布局 上滑时会展示里面所有内容,下滑时当没有多余内容时会响应上层BottomSheetBehavior, 从而达到,整体收缩的效果。
下面我贴上NestedScrollView的布局代码:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_80">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--渐变背景 -->
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_80"
android:background="@drawable/shape_gradient_white" />
<!--主要内容-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center_horizontal"
android:orientation="vertical">
<!--今日天气简单的文字描述-->
<TextView
android:id="@+id/tv_today_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/dp_12"
android:textColor="@color/black_4"
android:textSize="@dimen/sp_14" />
<!--分割线-->
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_3"
android:background="@color/line" />
<!--今日详情-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_12"
android:text="今日详情"
android:textColor="@color/black_4"
android:textSize="@dimen/sp_18" />
<!--点分割线-->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/shape_dash_line" />
<!--今日天气详情数据列表-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_today_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_12"
android:layout_marginBottom="@dimen/dp_12"
android:paddingLeft="@dimen/dp_12"
android:paddingRight="@dimen/dp_12" />
<!--点分割线-->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/shape_dash_line" />
<!--未来预报-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_12"
android:text="未来预报"
android:textColor="@color/black_4"
android:textSize="@dimen/sp_18" />
<!--未来七天天气预报-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_seven_day_daily"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/dp_12"
android:paddingRight="@dimen/dp_12" />
<!--查看更多天气预报-->
<TextView
android:id="@+id/tv_more_daily"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableRight="@mipmap/icon_more_gray"
android:gravity="center"
android:padding="@dimen/dp_12"
android:text="15日预报详情"
android:textColor="@color/gray_2" />
<!--分割线-->
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dp_3"
android:background="@color/line"
icon_more_gray.png
然后对里面的一些资源数据做讲解,里面用到了一些样式资源文件,在写之前,先把所有颜色值贴出来。注意是在mvplibrary下的colors.xml中
颜色代码如下:你可以复制粘贴进去
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="arc_bg_color">#C6D7F4</color>
<color name="arc_progress_color">#FBFEF7</color>
<color name="white">#ffffff</color><!--白色-->
<color name="black">#000000</color><!--黑色-->
<color name="black_2">#1E1E1A</color><!--黑色2-->
<color name="green">#77d034</color><!--绿色-->
<color name="blue_one">#9FC8E9</color><!--浅蓝色-->
<color name="transparent">#00000000</color><!--透明-->
<color name="transparent_bg">#22000000</color><!--黑色半透明-->
<color name="transparent_bg_white">#22FFFFFF</color><!--白色半透明-->
<color name="orange">#F38A50</color><!--橘色-->
<color name="shallow_orange">#FFEFD5</color><!--浅橘色-->
<color name="black_3">#454545</color><!--黑色3-->
<color name="gray">#BABABA</color><!--灰色-->
<color name="pink">#FFBCB3</color><!--粉色-->
<color name="pink_one">#FDEBE8</color><!--浅粉色-->
<color name="shallow_blue">#E7F3FC</color><!--浅蓝色 偏白-->
<color name="shallow_gray">#F2F2F2</color><!--浅灰色-->
<color name="dark_gray">#707070</color><!--深灰色-->
<color name="shallow_black">#6D6D6D</color><!--褐黑色-->
<color name="red">#FF0A00</color><!--红色-->
<color name="line_gray">#E3E5E8</color><!--灰色分割线-->
<color name="shallow_yellow">#E7C373</color><!--浅黄色-->
<color name="world_city_color">#243440</color>
<color name="blue_more">#C8DCFF</color><!--浅蓝色-->
<color name="gray_white">#F8F8F8</color><!--灰白-->
<color name="transparent_bg_2">#44000000</color><!--黑色半透明 二-->
<color name="transparent_bg_3">#66000000</color><!--黑色半透明 三-->
<color name="temp_max_tx">#FF7E45</color><!--高温文字颜色-->
<color name="temp_min_tx">#B3BCCA</color><!--低温文字颜色-->
<color name="white_2">#22FFFFFF</color><!--白色透明度22%-->
<color name="white_4">#44FFFFFF</color><!--白色透明度44%-->
<color name="white_6">#66FFFFFF</color><!--白色透明度66%-->
<color name="white_8">#88FFFFFF</color><!--白色透明度88%-->
<color name="purple">#56004f</color><!--紫色-->
<color name="gray_white_2">#F6F6F6</color><!--灰白2-->
<color name="gray_2">#626262</color><!--灰色2-->
<color name="black_4">#141414</color><!--黑色4-->
<color name="line">#DEDEE1</color><!--分割线-->
<color name="point_color">#D9D9D9</color><!--点分割颜色-->
<color name="gray_3">#818181</color><!--灰色3-->
<color name="back_white">#f7f8fa</color>
<color name="attention_text_light">#E9EAEF</color>
<color name="dark_text_color">#B9C0CA</color>
<color name="line_back_dark">#3f8DA0BA</color>
<color name="line_color">#919191</color>
<color name="search_light_un_color">#666666</color>
<color name="slategray">#708090</color><!--灰石色 -->
</resources>
下面是样式文件
首先是shape_gradient_white.xml,这是一个白色渐变的背景。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="@color/white_2"
android:centerColor="@color/white_6"
android:endColor="@color/white"
android:angle="270"
然后是shape_dash_line.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<size android:height="1dp" />
<stroke
android:dashGap="4dp"
android:dashWidth="4dp"
android:width="1dp"
android:color="@color/point_color"
然后是LinearLayout的布局代码:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/dp_160"
android:layout_marginLeft="@dimen/dp_12"
android:layout_marginRight="@dimen/dp_12"
android:background="@drawable/shape_blue_8"
android:orientation="vertical"
android:padding="@dimen/dp_12">
<!--城市-->
<TextView
android:id="@+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="城市"
android:textColor="@color/white"
android:textSize="@dimen/sp_16" />
<!--主要天气数据-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--温度-->
<TextView
android:id="@+id/tv_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0°"
android:textColor="@color/white"
android:textSize="60sp" />
<!--天气状态的图文显示、空气质量、风力-->
<LinearLayout
android:layout_width="@dimen/dp_0"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/dp_8"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<!--天气状态的图文显示-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<!--天气状态的文字描述-->
<TextView
android:id="@+id/tv_weather_state_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="天气状态"
android:textColor="@color/white"
android:textSize="@dimen/sp_14" />
<!--天气状况图片描述-->
<ImageView
android:id="@+id/iv_weather"
android:layout_width="@dimen/dp_36"
android:layout_height="@dimen/dp_36"
android:layout_marginLeft="@dimen/dp_12" />
</LinearLayout>
<!--空气质量、风力-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<!--空气质量-->
<TextView
android:id="@+id/tv_air"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_purple"
android:padding="@dimen/dp_2"
android:text="AQI 状态"
android:textColor="@color/purple"
android:textSize="@dimen/sp_14" />
<!--风信息描述-->
<TextView
android:id="@+id/tv_wind_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:text="风向风力"
android:textColor="@color/white"
android:textSize="@dimen/sp_14" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!--其他相关数据显示-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
android:orientation="horizontal">
<!--紫外线-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="紫外线"
android:textColor="@color/white_8" />
<TextView
android:id="@+id/tv_uvIndex"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:text=" "
android:textColor="@color/white" />
<!--湿度-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_16"
android:text="湿度"
android:textColor="@color/white_8" />
<TextView
android:id="@+id/tv_humidity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:text=" "
android:textColor="@color/white" />
<!--大气压-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_16"
android:text="大气压"
android:textColor="@color/white_8" />
<TextView
android:id="@+id/tv_pressure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:text=" "
android:textColor="@color/white"
首先是shape_blue_8.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="12dp" />
<gradient
android:startColor="@color/blue_one"
android:centerColor="@color/blue_one"
android:endColor="#6C84DC"
android:angle="225"
然后是shape_purple.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dip"
android:color="@color/purple" />
<corners android:radius="5dp"
其他的就没有了,OK,现在布局就已经是写好了。如果你需要完整的布局代码可以评论或者去我的GitHub上面看。
二、item布局
基本的布局写好了,但是里面还有两个列表,两个列表也是对应了两个布局xml的,也来看看吧,在app下的layout文件中新建两个xml文件分别是item_seven_day_daily_list.xml七天天气和item_today_detail.xml当前天气详情数据
item_seven_day_daily_list.xm代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:gravity="center_vertical"
android:paddingTop="@dimen/dp_12"
android:paddingBottom="@dimen/dp_12"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--日期-->
<TextView
android:id="@+id/tv_date"
android:text="1234"
android:textSize="@dimen/sp_14"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<!--天气描述 图标-->
<ImageView
android:id="@+id/iv_weather_state"
android:background="@mipmap/icon_100"
android:layout_width="30dp"
android:layout_height="30dp"/>
<!--最低温、最高温-->
<LinearLayout
android:gravity="right"
android:layout_width="@dimen/dp_0"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/tv_temp_height"
android:textSize="@dimen/sp_14"
android:textColor="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_temp_low"
android:textSize="@dimen/sp_14"
android:textColor="@color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<View
android:background="@color/gray_white_2"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"/>
</LinearLayout>
item_today_detail.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_5"
app:cardCornerRadius="@dimen/dp_6"
android:elevation="@dimen/dp_4">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingTop="@dimen/dp_16"
android:paddingBottom="@dimen/dp_16">
<ImageView
android:id="@+id/iv_icon"
android:scaleType="fitXY"
android:layout_width="@dimen/dp_30"
android:layout_height="@dimen/dp_30" />
<TextView
android:id="@+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
android:textColor="@color/black_4"
android:textSize="@dimen/sp_16" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
android:textColor="@color/gray_3"
android:textSize="@dimen/sp_14"
然后写适配器
三、适配器
在app下的adapter包中新建一个SevenDailyAdapter
代码如下:
package com.llw.goodweather.adapter;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.llw.goodweather.R;
import com.llw.goodweather.bean.DailyResponse;
import com.llw.goodweather.utils.DateUtils;
import com.llw.goodweather.utils.WeatherUtil;
import java.util.List;
/**
* 地图天气中 未来七天的天气列表适配器
*/
public class SevenDailyAdapter extends BaseQuickAdapter<DailyResponse.DailyBean, BaseViewHolder> {
public SevenDailyAdapter(int layoutResId, @Nullable List<DailyResponse.DailyBean> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, DailyResponse.DailyBean item) {
helper.setText(R.id.tv_date, DateUtils.dateSplitPlus(item.getFxDate()) +
DateUtils.Week(item.getFxDate()))//日期
.setText(R.id.tv_temp_height, item.getTempMax() + "℃")//最高温
.setText(R.id.tv_temp_low, " / " + item.getTempMin() + "℃");//最低温
//天气状态图片
ImageView weatherStateIcon = helper.getView(R.id.iv_weather_state);
int code = Integer.parseInt(item.getIconDay());//获取天气状态码,根据状态码来显示图标
WeatherUtil.changeIcon(weatherStateIcon, code);//调用工具类中写好的方法
}
}
再创建一个TodayDetailAdapter,代码如下:
package com.llw.goodweather.adapter;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.llw.goodweather.R;
import com.llw.goodweather.bean.TodayDetailBean;
import java.util.List;
/**
* 地图天气中 今日天气详情数据
*/
public class TodayDetailAdapter extends BaseQuickAdapter<TodayDetailBean, BaseViewHolder> {
public TodayDetailAdapter(int layoutResId, @Nullable List<TodayDetailBean> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, TodayDetailBean item) {
ImageView imageView = helper.getView(R.id.iv_icon);
imageView.setImageResource(item.getIcon());//图标
helper.setText(R.id.tv_value,item.getValue())//值
.setText(R.id.tv_name,item.getName());//名称
}
}
适配器写好了,下面写订阅器
四、订阅器
在app下的contract包下新建一个MapWeatherContract,这个里面放置的就是需要使用的网络请求方法的配置,在Activity里面当前需要什么就放置什么,包含请求和返回方法,代码如下:
package com.llw.goodweather.contract;
import com.llw.goodweather.api.ApiService;
import com.llw.goodweather.bean.AirNowResponse;
import com.llw.goodweather.bean.DailyResponse;
import com.llw.goodweather.bean.NewSearchCityResponse;
import com.llw.goodweather.bean.NowResponse;
import com.llw.mvplibrary.base.BasePresenter;
import com.llw.mvplibrary.base.BaseView;
import com.llw.mvplibrary.net.NetCallBack;
import com.llw.mvplibrary.net.ServiceGenerator;
import retrofit2.Call;
import retrofit2.Response;
/**
* 地图天气订阅器
*/
public class MapWeatherContract {
public static class MapWeatherPresenter extends BasePresenter<IMapWeatherView> {
/**
* 搜索城市 V7版本中 需要把定位城市的id查询出来,然后通过这个id来查询详细的数据
* @param location 城市名
*/
public void searchCity(String location) {//注意这里的4表示新的搜索城市地址接口
ApiService service = ServiceGenerator.createService(ApiService.class, 4);//指明访问的地址
service.newSearchCity(location,"exact").enqueue(new NetCallBack<NewSearchCityResponse>() {
@Override
public void onSuccess(Call<NewSearchCityResponse> call, Response<NewSearchCityResponse> response) {
if(getView() != null){
getView().getNewSearchCityResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getDataFailed();
}
}
});
}
/**
* 实况天气 V7版本
* @param location 城市名
*/
public void nowWeather(String location){//这个3 表示使用新的V7API访问地址
ApiService service = ServiceGenerator.createService(ApiService.class,3);
service.nowWeather(location).enqueue(new NetCallBack<NowResponse>() {
@Override
public void onSuccess(Call<NowResponse> call, Response<NowResponse> response) {
if(getView() != null){
getView().getNowResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getDataFailed();
}
}
});
}
/**
* 天气预报 V7版本 7d 表示天气的数据 为了和之前看上去差别小一些,这里先用七天的
* @param location 城市名
*/
public void dailyWeather(String location){//这个3 表示使用新的V7API访问地址
ApiService service = ServiceGenerator.createService(ApiService.class,3);
service.dailyWeather("7d",location).enqueue(new NetCallBack<DailyResponse>() {
@Override
public void onSuccess(Call<DailyResponse> call, Response<DailyResponse> response) {
if(getView() != null){
getView().getDailyResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getDataFailed();
}
}
});
}
/**
* 当天空气质量
* @param location 城市名
*/
public void airNowWeather(String location){
ApiService service = ServiceGenerator.createService(ApiService.class,3);
service.airNowWeather(location).enqueue(new NetCallBack<AirNowResponse>() {
@Override
public void onSuccess(Call<AirNowResponse> call, Response<AirNowResponse> response) {
if(getView() != null){
getView().getAirNowResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getDataFailed();
}
}
});
}
}
public interface IMapWeatherView extends BaseView {
//搜索城市返回城市id 通过id才能查下面的数据,否则会提示400 V7
void getNewSearchCityResult(Response<NewSearchCityResponse> response);
//实况天气
void getNowResult(Response<NowResponse> response);
//天气预报 7天
void getDailyResult(Response<DailyResponse> response);
//空气质量
void getAirNowResult(Response<AirNowResponse> response);
//错误返回
void getDataFailed();
}
}
五、数据渲染
打开MapWeatherActivity,
完成上面一步,然后实现里面的方法。分别是
@Override
protected MapWeatherContract.MapWeatherPresenter createPresent() {
return new MapWeatherContract.MapWeatherPresenter();
}
/**
* 搜索城市返回
*
* @param response
*/
@Override
public void getNewSearchCityResult(Response<NewSearchCityResponse> response) {
}
/**
* 实况天气返回
*
* @param response
*/
@Override
public void getNowResult(Response<NowResponse> response) {
}
/**
* 未来七天天气预报数据返回
*
* @param response
*/
@Override
public void getDailyResult(Response<DailyResponse> response) {
}
/**
* 空气质量数据返回
*
* @param response
*/
@Override
public void getAirNowResult(Response<AirNowResponse> response) {
}
/**
* 错误返回
*/
@Override
public void getDataFailed() {
}
方法有了,现在通过注解绑定控件id
@BindView(R.id.tv_city)
TextView tvCity;//城市
@BindView(R.id.iv_weather)
ImageView ivWeather;//天气状态图片描述
@BindView(R.id.tv_temperature)
TextView tvTemperature;//温度
@BindView(R.id.tv_weather_state_tv)
TextView tvWeatherStateTv;//天气状态文字描述
@BindView(R.id.tv_wind_info)
TextView tvWindInfo;//风力风向
@BindView(R.id.rv_today_detail)
RecyclerView rvTodayDetail;//今日详情数据列表
@BindView(R.id.rv_seven_day_daily)
RecyclerView rvSevenDayDaily;//七天天气预报列表
@BindView(R.id.tv_more_daily)
TextView tvMoreDaily;//15日天气预报数据
@BindView(R.id.tv_uvIndex)
TextView tvUvIndex;//紫外线强度
@BindView(R.id.tv_humidity)
TextView tvHumidity;//湿度
@BindView(R.id.tv_pressure)
TextView tvPressure;//大气压
@BindView(R.id.tv_today_info)
TextView tvTodayInfo;//今日天气简要描述
@BindView(R.id.tv_air)
TextView tvAir;//空气质量
@BindView(R.id.bottom_sheet_ray)
RelativeLayout bottomSheetRay;//底部拖动布局
声明需要的数据
private String locationId;//城市id
private List<DailyResponse.DailyBean> dailyList = new ArrayList<>();//七天天气预报
List<TodayDetailBean> todayDetailList = new ArrayList<>();//当前天气详情
private SevenDailyAdapter mSevenDailyAdapter;//七天天气预报适配器
private String dayInfo;//今天白天天气描述
private String nightInfo;//今天晚上天气描述
private BottomSheetBehavior bottomSheetBehavior;//底部控件
还有一个就是点击事件的改变,之前是只有一个浮动按钮的点击事件,现在多了一个,所以用switch来解决,15日天气预报详情就点击到之前我写好的一个Activity里面,传入数据。当然你现在点击传过去是会出问题的,因为还没有赋值的。
/**
* 点击事件
*/
@OnClick({R.id.btn_auto_location,R.id.tv_more_daily})
public void onViewClicked(View view) {
switch (view.getId()){
case R.id.btn_auto_location://重新定位
markerLatitude = 0;
markerLongitude = 0;
marker.remove();//清除标点
initLocation();
break;
case R.id.tv_more_daily://15日天气预报详情
Intent intent = new Intent(context, MoreDailyActivity.class);
intent.putExtra("locationId", locationId);
intent.putExtra("cityName", tvCity.getText().toString());
startActivity(intent);
break;
}
}
在上一篇文章中,通过自动定位和手动定位(点击地图定位),在定位返回监听中,通过经纬度的反编译解码得到了实际的所在位置,也就是省、市、区/县、街道等一些数据,但是我只需要一个区/县即可。
在解码后请求这个信息来搜索城市相关信息,然后在搜索城市的返回方法中做处理,来看这个返回方法。
/**
* 搜索城市返回
*
* @param response
*/
@Override
public void getNewSearchCityResult(Response<NewSearchCityResponse> response) {
if (response.body().getStatus().equals(Constant.SUCCESS_CODE)) {
if (response.body().getLocation() != null && response.body().getLocation().size() > 0) {
tvCity.setText(response.body().getLocation().get(0).getName());//城市
locationId = response.body().getLocation().get(0).getId();//城市Id
showLoadingDialog();
mPresent.nowWeather(locationId);//查询实况天气
mPresent.dailyWeather(locationId);//查询天气预报
mPresent.airNowWeather(locationId);//空气质量
} else {
ToastUtils.showShortToast(context, "数据为空");
}
} else {
tvCity.setText("查询城市失败");
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getStatus()));
}
}
在返回中设置城市的名称,给全局变量赋值,这样我点击15日天气预报传过去才有数据。你要知道页面渲染的步骤,当我能够点击按钮时,这个时候数据就都有了。然后请求另外三个接口方法,在返回中做处理,当然后期还会做优化,会涉及到网络状态、数据存储等地方,一步一步来,一口是吃不成胖子的。
/**
* 实况天气返回
*
* @param response
*/
@Override
public void getNowResult(Response<NowResponse> response) {
if (response.body().getCode().equals(Constant.SUCCESS_CODE)) {//200则成功返回数据
NowResponse data = response.body();
if (data != null) {
Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Light.ttf");
tvTemperature.setText(response.body().getNow().getTemp() + "°");//温度
tvTemperature.setTypeface(typeface);//使用字体
tvWeatherStateTv.setText(data.getNow().getText());//天气状态文字描述
WeatherUtil.changeIcon(ivWeather, Integer.parseInt(data.getNow().getIcon()));
tvWindInfo.setText(data.getNow().getWindDir() + data.getNow().getWindScale() + "级");
tvHumidity.setText(data.getNow().getHumidity() + "%");//湿度
tvPressure.setText(data.getNow().getPressure() + "hPa");//大气压
//今日详情
todayDetailList.clear();
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_temp, data.getNow().getFeelsLike() + "°", "体感温度"));
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_precip, data.getNow().getPrecip() + "mm", "降水量"));
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_humidity, data.getNow().getHumidity() + "%", "湿度"));
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_pressure, data.getNow().getPressure() + "hPa", "大气压强"));
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_vis, data.getNow().getVis() + "KM", "能见度"));
todayDetailList.add(new TodayDetailBean(R.mipmap.icon_today_cloud, data.getNow().getCloud() + "%", "云量"));
TodayDetailAdapter adapter = new TodayDetailAdapter(R.layout.item_today_detail, todayDetailList);
rvTodayDetail.setLayoutManager(new GridLayoutManager(context, 3));
rvTodayDetail.setAdapter(adapter);
adapter.notifyDataSetChanged();
} else {
ToastUtils.showShortToast(context, "暂无实况天气数据");
}
} else {//其他状态返回提示文字
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode()));
}
}
一些基础数据的赋值,然后组装数据到适配器中渲染。里面用到了6个小图标
icon_today_temp.png
icon_today_pressure.png
icon_today_cloud.png
icon_today_vis.png
icon_today_precip.png
icon_today_humidity.png
然后看下一个返回方法
所有在initView中初始化,当然你也可以把三行代码直接放到返回中也可以
= new SevenDailyAdapter(R.layout.item_seven_day_daily_list, dailyList);
rvSevenDayDaily.setLayoutManager(new LinearLayoutManager(context));
rvSevenDayDaily.setAdapter(mSevenDailyAdapter);
在返回中,
/**
* 未来七天天气预报数据返回
*
* @param response
*/
@Override
public void getDailyResult(Response<DailyResponse> response) {
if (response.body().getCode().equals(Constant.SUCCESS_CODE)) {
List<DailyResponse.DailyBean> data = response.body().getDaily();
if (data != null && data.size() > 0) {//判空处理
for (int i = 0; i < data.size(); i++) {
if (data.get(i).getFxDate().equals(DateUtils.getNowDate())) {//今天
dayInfo = data.get(i).getTextDay();
nightInfo = data.get(i).getTextNight();
tvUvIndex.setText(WeatherUtil.uvIndexInfo(data.get(i).getUvIndex()));//紫外线强度
}
}
dailyList.clear();//添加数据之前先清除
dailyList.addAll(data);//添加数据
mSevenDailyAdapter.notifyDataSetChanged();//刷新列表
} else {
ToastUtils.showShortToast(context, "天气预报数据为空");
}
} else {//异常状态码返回
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode()));
}
}
这个也是常规的操作了,相信不用说明了。下一个
/**
* 空气质量数据返回
*
* @param response
*/
@Override
public void getAirNowResult(Response<AirNowResponse> response) {
dismissLoadingDialog();
if (response.body().getCode().equals(Constant.SUCCESS_CODE)) {
AirNowResponse.NowBean data = response.body().getNow();
if (response.body().getNow() != null) {
tvAir.setText("AQI " + data.getCategory());
tvTodayInfo.setText("今天白天" + dayInfo + ",晚上" + nightInfo + ",现在" + tvTemperature.getText().toString() + "," + WeatherUtil.apiToTip(data.getCategory()));
} else {
ToastUtils.showShortToast(context, "空气质量数据为空");
}
}
}
这个里面有一个apiToTip方法是我新增的,打开WeatherUtil,新增方法代码如下:
/**
* 根据api的提示转为更为人性化的提醒
* @param apiInfo
* @return
*/
public static String apiToTip(String apiInfo){
String result = null;
String str = null;
if(apiInfo.contains("AQI ")){
str = apiInfo.replace("AQI ", " ");
}else {
str = apiInfo;
}
switch (str){//优,良,轻度污染,中度污染,重度污染,严重污染
case "优":
result = "♪(^∇^*) 空气很好。";
break;
case "良":
result = "ヽ(✿゚▽゚)ノ 空气不错。";
break;
case "轻度污染":
result = "(⊙﹏⊙) 空气有些糟糕。";
break;
case "中度污染":
result = " ε=(´ο`*)))唉 空气污染较为严重,注意防护。";
break;
case "重度污染":
result = "o(≧口≦)o 空气污染很严重,记得戴口罩哦!";
break;
case "严重污染":
result = "ヽ(*。>Д<)o゜ 完犊子了!空气污染非常严重,要减少出门,定期检查身体,能搬家就搬家吧!";
break;
}
return result;
}
最后在错误返回时,一般是网络很差或者没有网络是会提示你。
/**
* 错误返回
*/
@Override
public void getDataFailed() {
ToastUtils.showShortToast(context, "连接超时,稍后尝试。");
}
数据是有了,但是页面的一些布局效果要再修改一下。
六、页面效果优化
android:id="@+id/btn_auto_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:layout_marginTop="@dimen/dp_20"
android:clickable="true"
android:src="@mipmap/icon_auto_location"
app:backgroundTint="@color/transparent_bg_3"
app:backgroundTintMode="screen"
app:borderWidth="@dimen/dp_0"
app:fabSize="mini"
app:hoveredFocusedTranslationZ="@dimen/dp_18"
app:pressedTranslationZ="@dimen/dp_18"
app:rippleColor="@color/blue_one"
修改一个activity_map_weather.xml中的浮动按钮,我改动了一下这个按钮的显示位置,现在会出现在屏幕的左上角,当然这个按钮还需要和我们的协调布局做一些效果,就是当我向上拖动底部布局时,此时如果是手动定位则浮动按钮隐藏,向下收缩则浮动按钮显示。
所在要在initView加入,上下拖动的监听。
/*获取behavior 控制bottomsheet的 显示 与隐藏*/
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetRay);
/*bottomSheet 的 状态改变 根据不同的状态 做不同的事情*/
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_COLLAPSED://收缩
//手动定位时,收缩就要显示浮动按钮,因为这时候你可以操作地图了
if (markerLatitude != 0) {//自动定位
btnAutoLocation.show();//显示自动定位按钮
}
break;
case BottomSheetBehavior.STATE_EXPANDED://展开
//手动定位时,展开就要隐藏浮动按钮,因为这时候你是没有办法操作地图的
if (markerLatitude != 0) {//自动定位
btnAutoLocation.hide();//隐藏自动定位按钮
}
break;
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
/*slideOffset bottomSheet 的 移动距离*/
}
});
至此数据就写完了,来看一下运行的效果吧
这个APP还没有结束,未完待续
源码地址:GoodWeather 欢迎 Star 和 Fork
下一篇:Android 天气APP(二十六)增加自动更新(检查版本、通知栏下载、自动安装)