Android 天气APP(二十五)地图天气(下)嵌套滑动布局渲染天气数据

时间:2022-07-25
本文章向大家介绍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" />
                        
                        <!--未完待续。。。-->
                    </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还没有结束,未完待续

源码如下: Good Weather 欢迎Star或者Fork 联系邮箱 lonelyholiday@qq.com