上篇文章中,完成了对地图的控制,那么这篇文章中完成对天气数据的渲染。
完成这篇文章实现的效果如下,如果你觉得不行那就可以不用看下面了。
一、嵌套布局
在上一篇文章中,实现地图的功能,只用了一个地图控件和一个浮动按钮。而在这一篇文章中,为了提高页面的可用性和用户交互的效果,我用了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" /> <!--未完待续。。。--> </LinearLayout> </LinearLayout> </androidx.core.widget.NestedScrollView>
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>
然后是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" /> </shape>
然后是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" /> </LinearLayout> </LinearLayout>
首先是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>
然后是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" /> </shape>
其他的就没有了,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" /> </LinearLayout> </androidx.cardview.widget.CardView> </LinearLayout>
然后写适配器
三、适配器
在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中初始化,当然你也可以把三行代码直接放到返回中也可以
mSevenDailyAdapter = 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, "连接超时,稍后尝试。"); }
数据是有了,但是页面的一些布局效果要再修改一下。
六、页面效果优化
<!--浮动按钮--> <com.google.android.material.floatingactionbutton.FloatingActionButton 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还没有结束,未完待续