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

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

上篇文章中,完成了对地图的控制,那么这篇文章中完成对天气数据的渲染。

完成这篇文章实现的效果如下,如果你觉得不行那就可以不用看下面了。


image.gif


一、嵌套布局


在上一篇文章中,实现地图的功能,只用了一个地图控件和一个浮动按钮。而在这一篇文章中,为了提高页面的可用性和用户交互的效果,我用了CoordinatorLayout,这是一个嵌套滑动布局。


接下来来看看详细的布局内容:


20200827163804488.png


然后来看这个里面放了什么


20200827164303176.png


这里我放了一个相对布局,这是用于控制滑动的布局 在页面的底部留有一部分布局,可以通过向上拖动到屏幕的底部,不过为了更好地效果,我在CoordinatorLayout中设置50的上边距。


然后再看这个相对布局里面是什么内容


20200827165612126.png


展开之后里面是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


20200828094942928.png


然后对里面的一些资源数据做讲解,里面用到了一些样式资源文件,在写之前,先把所有颜色值贴出来。注意是在mvplibrary下的colors.xml中


20200827170516441.png


颜色代码如下:你可以复制粘贴进去


<?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当前天气详情数据


20200827171511384.png


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,


20200828091551150.png


完成上面一步,然后实现里面的方法。分别是


  @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;
        }
    }


在上一篇文章中,通过自动定位和手动定位(点击地图定位),在定位返回监听中,通过经纬度的反编译解码得到了实际的所在位置,也就是省、市、区/县、街道等一些数据,但是我只需要一个区/县即可。


20200828093336852.png


在解码后请求这个信息来搜索城市相关信息,然后在搜索城市的返回方法中做处理,来看这个返回方法。


  /**
     * 搜索城市返回
     *
     * @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个小图标


20200828094844400.png


icon_today_temp.png


20200828095010705.png


icon_today_pressure.png


20200828095010704.png


icon_today_cloud.png


20200828095010695.png


icon_today_vis.png


20200828095010707.png


icon_today_precip.png


20200828095010697.png


icon_today_humidity.png


20200828095010696.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 的 移动距离*/
            }
        });


至此数据就写完了,来看一下运行的效果吧


20200828101017101.gif


这个APP还没有结束,未完待续


相关文章
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
139 0
安卓项目:app注册/登录界面设计
|
2月前
|
开发工具
uniapp, 短剧视频类App实现参考,支持滑动播放,仿抖音 仿陌陌 短视频 无限滑动播放 视频流
阿里云点播服务web播放器sdk,短剧视频类App实现参考。仿抖音 仿陌陌 短视频 无限滑动播放 视频流。无uniapp video 原生组件的层级、遮挡、覆盖问题,适合与不同功能视图组合使用,实现丰富的应用功能。
uniapp, 短剧视频类App实现参考,支持滑动播放,仿抖音 仿陌陌 短视频 无限滑动播放 视频流
|
1月前
|
JSON API 网络安全
App数据的爬取
App数据的爬取
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
158 2
|
2月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
102 3
|
1月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
216 0
|
2月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
定位技术 API Android开发
Android——集地图、定位、导航于一体
电子地图 地图 修改定位图标 定位 导航 尾言
153 0
|
3天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
5天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。

热门文章

最新文章