文本最终效果图
前言
本来这一篇文章应该和上一篇放到一起的,但是考虑到篇幅的问题,我就分成两篇文章了,我真的很怕读者看的时候失去动力,动不动就七八万字的博客,看着就害怕。虽然主要是代码比较多,中间穿插一些讲解而已。开始吧!
正文
我相信很多APP都会有这个欢迎页的,也就是启动页面,常规的就是一个页面展示APP的定位,还有就是广告之类的。这个页面更多的功能其实是对APP冷启动和数据的处理,相当于一个缓冲区。先来看一下白屏黑屏的效果
可以看到虽然这个GIF很多,白屏和黑屏的时间也很短,一刹那间就过去了,但这个就是细节啊,你不处理能行吗?
再看优化后的
这样虽然说看上去没有啥太大的作用,但是体验就会比较好呀,你说呢?
好了接下来看怎么实现的。
一、欢迎页及黑白屏处理
先创建一个SplashActivity的EmptyActivity,
这里放入启动页的背景图片
然后修改布局文件activity_splash.xml
直接改为ImageView,OK,现在这里就不用管了,进入AndroidManifest.xml
将MainActivit下面的intent-filter剪切到SplashActivity下来,意思就是把SplashActivity作为第一个页面。
进入styles.xml新增
<item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item><!--透明背景-->
如下图所示
这个意思就是将APP的所以主题背景改为透明,这样就不存在黑屏白屏的问题了,现在你运行一下之后就不会有这个黑屏白屏了,其实这种处理方式不止一种,更多的方法给我留言,我会考虑单独写一篇博客来讲这个白屏和黑屏的处理。然后我们要在SplashActivity中进行页面的跳转。
写一个延时跳转方法
/** * 进入主页面 */ private void goToMain() { new Handler().postDelayed(new Runnable() { @Override public void run() { finish(); Intent intent = new Intent(context, MainActivity.class); startActivity(intent); } }, 1000); }
然后在onCreate方法中调用即可。因为现在所有Activity的背景色都变了透明,所以记得在每个Acitivity对应的布局文件中,在主布局中,如果没有设置背景颜色就增加背景颜色,通常是白色就可以了,否则会出现诡异的现象。
这里先告一段落。
二、世界城市
首先把之前的关于热门城市的东西都删掉,这个里面和热门城市就已经没有关系了。
首先要获取到世界国家/地区的列表。和风提供的国家/地区的城市代码是用的.csv格式,也就是说需要在Android中需要读取CSV文件中的数据读取。可以看看这一篇文章Android 读取csv格式数据文件,
这是我自己弄好的一个文件,和风的都是英文的,所以我就自己翻译好了,需要的就直接到项目中去下载好了,像这种文件,通常都是放在欢迎页中就要完成数据读取的。这里使用Sqlite来保存这些数据吧。在mvplibrary中的bean中新建一个Country实体
代码如下:
package com.llw.mvplibrary.bean; import org.litepal.crud.LitePalSupport; public class Country extends LitePalSupport { private String name;//名称 private String code;//代码 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } }
新增一个映射,然后版本改为2。
数据库有了,然后就是数据读取和填充了,回到SplashActivity
新增如下代码:
private List<Country> list;//数据列表 private void initCountryData() { list = LitePal.findAll(Country.class); if (list.size() > 0){//有数据了 goToMain(); }else {//第一次加载 InputStreamReader is = null; try { is = new InputStreamReader(getAssets().open("world_country.csv"), "UTF-8"); BufferedReader reader = new BufferedReader(is); reader.readLine(); String line; while ((line = reader.readLine()) != null) { String[] result = line.split(","); Country country = new Country(); country.setName(result[0]); country.setCode(result[1]); country.save(); } goToMain(); } catch (IOException e) { e.printStackTrace(); } } }
在这方法中,先获取是否存在数据,不存在则读取文件中的数据,遍历每一行,遍历之后逗号截取为字符串数组分别赋值,最后保存数据,保存好之后则进入主页面,如果已有数据则直接进入主页面。其实我们还可以把权限请求也放到这个里面来,这样就不用在MainActivity中进行动态权限请求了。很多APP都会在第一启动的时候请求所需要的权限,达到一劳永逸。
现在只要进入到MainActivity中就开始定位,当然如果你没有权限你就看不到这个页面。
现在回到SplashActivity中,先继承BaseActivity,实现两个对应的方法,删除onCreate方法。
private RxPermissions rxPermissions;//权限请求框架 @Override public void initData(Bundle savedInstanceState) { StatusBarUtil.transparencyBar(context);//透明状态栏 rxPermissions = new RxPermissions(this);//实例化这个权限请求框架,否则会报错 permissionVersion();//权限判断 } //权限判断 private void permissionVersion() { if (Build.VERSION.SDK_INT >= 23) {//6.0或6.0以上 //动态权限申请 permissionsRequest(); } else {//6.0以下 //发现只要权限在AndroidManifest.xml中注册过,均会认为该权限granted 提示一下即可 ToastUtils.showShortToast(this, "你的版本在Android6.0以下,不需要动态申请权限。"); } } //动态权限申请 private void permissionsRequest() {//使用这个框架需要制定JDK版本,建议用1.8 rxPermissions.request(Manifest.permission.ACCESS_FINE_LOCATION) .subscribe(granted -> { if (granted) {//申请成功 //得到权限可以进入APP //加载世界国家数据到本地数据库,已有则不加载 initCountryData(); } else {//申请失败 finish(); ToastUtils.showShortToast(this, "权限未开启"); } }); }
这个代码之前我已经解释过一次,就不再做解释了。现在这个欢迎页的使命就已经完成了。OK,世界城市数据有了,下面就是怎么显示的问题了。
在app的ui包下,新建WorldCityActivity。然后修改activity_world_city.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:fitsSystemWindows="true" android:background="@color/shallow_gray" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.WorldCityActivity"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/white" app:layout_constraintEnd_toEndOf="parent" app:navigationIcon="@mipmap/icon_return" app:contentInsetLeft="@dimen/dp_16" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:popupTheme="@style/AppTheme.PopupOverlay"> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="@dimen/sp_16" android:textColor="@color/black" android:text="国家/地区" /> </androidx.appcompat.widget.Toolbar> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv" android:background="@color/white" android:layout_marginTop="@dimen/dp_2" android:paddingBottom="@dimen/dp_10" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
在contract包下新建一个WorldCityContract
代码如下:
package com.llw.goodweather.contract; import com.llw.goodweather.api.ApiService; import com.llw.goodweather.bean.WorldCityResponse; 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 WorldCityContract { public static class WorldCityPresenter extends BasePresenter<IWorldCityView> { /** * 世界城市 V7 * @param range 类型 */ public void worldCity(String range) { ApiService service = ServiceGenerator.createService(ApiService.class, 4);//指明访问的地址 service.worldCity(range).enqueue(new NetCallBack<WorldCityResponse>() { @Override public void onSuccess(Call<WorldCityResponse> call, Response<WorldCityResponse> response) { if(getView() != null){ getView().getWorldCityResult(response); } } @Override public void onFailed() { if(getView() != null){ getView().getDataFailed(); } } }); } } public interface IWorldCityView extends BaseView { //热门城市返回数据 V7 void getWorldCityResult(Response<WorldCityResponse> response); //错误返回 void getDataFailed(); } }
在layout下新建一个item_country_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="@color/white" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_country_name" android:text="国家" android:padding="@dimen/dp_16" android:textColor="@color/black" android:textSize="@dimen/sp_16" android:ellipsize="end" android:background="?android:attr/selectableItemBackground" android:maxLines="1" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:layout_marginLeft="@dimen/dp_16" android:background="@color/line_gray" android:layout_width="match_parent" android:layout_height="@dimen/dp_1"/> </LinearLayout>
用于展示世界上的国家/地区
然后就是适配器了。在adapter下新建一个CountryAdapter,代码如下:
package com.llw.goodweather.adapter; 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.mvplibrary.bean.Country; import java.util.List; /** * 国家列表适配器 */ public class CountryAdapter extends BaseQuickAdapter<Country, BaseViewHolder> { public CountryAdapter(int layoutResId, @Nullable List<Country> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder helper, Country item) { helper.setText(R.id.tv_country_name,item.getName()); helper.addOnClickListener(R.id.tv_country_name); } }
继承MvpActivity,然后实现方法,下面会逐个说明
初始化这个页面控件,和创建对象
@BindView(R.id.tv_title) TextView tvTitle; @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.rv) RecyclerView rv; CountryAdapter mAdapter; List<Country> mList = new ArrayList<>();
在initData中,这个其实就是取代了onCreate,所以onCreate可以删掉了。
@Override public void initData(Bundle savedInstanceState) { StatusBarUtil.setStatusBarColor(context, R.color.white);//白色底 状态栏 StatusBarUtil.StatusBarLightMode(context);//黑色字体 Back(toolbar); initList(); }
@Override public int getLayoutId() { return R.layout.activity_world_city; } @Override protected WorldCityContract.WorldCityPresenter createPresent() { return new WorldCityContract.WorldCityPresenter(); }
/** * 初始化列表数据 */ private void initList() { mList = LitePal.findAll(Country.class); mAdapter = new CountryAdapter(R.layout.item_country_list, mList); rv.setLayoutManager(new LinearLayoutManager(context)); rv.setAdapter(mAdapter); mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { @Override public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { showLoadingDialog(); mPresent.worldCity(mList.get(position).getCode()); } }); }
/** * 世界城市返回 * @param response */ @Override public void getWorldCityResult(Response<WorldCityResponse> response) { } /** * 失败异常返回 */ @Override public void getDataFailed() { dismissLoadingDialog(); ToastUtils.showShortToast(context,"其他异常"); }
现在只要运行就会看到国家/地区数据
然后做这个点击之后的城市弹窗
首先是弹窗的布局。
在layout下新建window_world_city_list.xml
代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:fitsSystemWindows="true" android:background="@color/white" android:layout_width="wrap_content" android:layout_height="match_parent" tools:ignore="MissingDefaultResource"> <TextView android:id="@+id/tv_title" android:gravity="center" android:textColor="@color/black" android:padding="@dimen/dp_16" android:textSize="@dimen/sp_16" android:textStyle="bold" android:layout_width="@dimen/dp_240" android:layout_height="?attr/actionBarSize"/> <View android:layout_width="@dimen/dp_240" android:layout_height="@dimen/dp_2" android:background="@color/line_gray"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_city" android:layout_width="@dimen/dp_240" android:layout_height="match_parent"/> </LinearLayout>
在adapter中新建一个WorldCityAdapter,代码如下:
package com.llw.goodweather.adapter; 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.WorldCityResponse; import java.util.List; /** * 国家/地区中的城市适配器 */ public class WorldCityAdapter extends BaseQuickAdapter<WorldCityResponse.TopCityListBean, BaseViewHolder> { public WorldCityAdapter(int layoutResId, @Nullable List<WorldCityResponse.TopCityListBean> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder helper, WorldCityResponse.TopCityListBean item) { helper.setText(R.id.tv_city,item.getName()); helper.addOnClickListener(R.id.tv_city); } }
回到WorldCityActivity
新增
点击列表中某一个国家,然后获取到这个code,通过code来请求接口获取城市数据,然后返回中将城市的数据传递到弹窗中,在弹窗中渲染数据。
城市弹窗代码如下:
/** * 城市弹窗 */ private void showCityWindow(String countryName,List<WorldCityResponse.TopCityListBean> list) { LiWindow liWindow = new LiWindow(context); final View view = LayoutInflater.from(context).inflate(R.layout.window_world_city_list, null); TextView windowTitle = (TextView) view.findViewById(R.id.tv_title); windowTitle.setText(countryName); RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.rv_city); liWindow.showRightPopupWindowMatchParent(view);//显示弹窗 mCityAdapter = new WorldCityAdapter(R.layout.item_city_list,list); recyclerView.setLayoutManager(new LinearLayoutManager(context)); recyclerView.setAdapter(mCityAdapter); mCityAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { @Override public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { Intent intent = new Intent(context, WorldCityWeatherActivity.class); intent.putExtra("name",list.get(position).getName()); intent.putExtra("locationId",list.get(position).getId()); startActivity(intent); liWindow.closePopupWindow(); } }); }
到此为止,世界城市这个也买那就写完了,然后就写这个城市点击之后的天气查询了。在ui包下新建一个WorldCityWeatherActivity,作为点击跳转的Activity。
在修改布局之前先在mvplibrary下的values中的colors.xml中新增一个
<color name="world_city_color">#243440</color>
然后修改activity_world_city_weather.xml
这里面用到一个icon_hot_city_bg_2的图片
这里提供两个给你选择
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:background="@color/world_city_color" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.WorldCityWeatherActivity"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:background="@mipmap/icon_hot_city_bg_2" android:layout_width="match_parent" android:layout_height="wrap_content" app:contentInsetStart="0dp" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:padding="@dimen/dp_12" android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="城市" android:textColor="@color/white" android:textSize="@dimen/sp_18" /> <!--温度--> <RelativeLayout android:padding="@dimen/dp_12" android:gravity="top" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <!--气候图标--> <ImageView android:id="@+id/iv_weather_state" android:layout_width="@dimen/dp_150" android:layout_height="@dimen/dp_150" /> <LinearLayout android:layout_marginRight="@dimen/dp_20" android:layout_alignParentRight="true" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal"> <TextView android:layout_alignParentRight="true" android:id="@+id/tv_temperature" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0°" android:textColor="@color/white" android:textSize="@dimen/sp_48" /> <TextView android:id="@+id/tv_weather_state" android:layout_toRightOf="@+id/tv_temperature" android:text="天气状态" android:textColor="@color/white" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <!--最高温和最低温--> <LinearLayout android:layout_marginTop="@dimen/dp_8" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_tem_max" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/dp_8" android:textColor="@color/white" android:textSize="@dimen/sp_14" /> <TextView android:id="@+id/tv_tem_min" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/dp_8" android:alpha="0.5" android:textColor="@color/white" android:textSize="@dimen/sp_14" /> </LinearLayout> <!--风信息--> <TextView android:layout_marginTop="@dimen/dp_8" android:textSize="@dimen/sp_14" android:id="@+id/tv_wind_state" android:textColor="@color/white" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </RelativeLayout> </LinearLayout> </androidx.appcompat.widget.Toolbar> </com.google.android.material.appbar.AppBarLayout> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_hourly" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/world_city_color" /> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout>
这里页面用了协调布局,形成折叠效果,具体的说明可以看这一篇文章Android 折叠式布局,这也是之前写的文章了,说明可能会详细一些,可以看看。
布局写好之后,在app中的contract下创建一个WorldCityWeatherContract订阅器,代码如下:
package com.llw.goodweather.contract; import com.llw.goodweather.api.ApiService; import com.llw.goodweather.bean.DailyResponse; import com.llw.goodweather.bean.HourlyResponse; 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 WorldCityWeatherContract { public static class WorldCityWeatherPresenter extends BasePresenter<IWorldCityWeatherView> { /** * 实况天气 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(); } } }); } /** * 逐小时预报(未来24小时) * @param location 城市名 */ public void hourlyWeather(String location){ ApiService service = ServiceGenerator.createService(ApiService.class,3); service.hourlyWeather(location).enqueue(new NetCallBack<HourlyResponse>() { @Override public void onSuccess(Call<HourlyResponse> call, Response<HourlyResponse> response) { if(getView() != null){ getView().getHourlyResult(response); } } @Override public void onFailed() { if(getView() != null){ getView().getDataFailed(); } } }); } } public interface IWorldCityWeatherView extends BaseView { /* 以下为V7版本新增 */ //实况天气 void getNowResult(Response<NowResponse> response); //天气预报 7天 void getDailyResult(Response<DailyResponse> response); //逐小时天气预报 void getHourlyResult(Response<HourlyResponse> response); //错误返回 void getDataFailed(); } }
在layout下新建一个item_weather_hourly_world_list.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" android:gravity="center_vertical" android:orientation="horizontal" android:paddingLeft="@dimen/dp_16" android:paddingRight="@dimen/dp_16"> <!--时间--> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="上午10:00" android:textColor="#FFF" android:textSize="14sp" /> <!--气候图标--> <RelativeLayout android:layout_width="@dimen/dp_70" android:layout_height="@dimen/dp_70"> <View android:layout_width="@dimen/dp_1" android:layout_height="match_parent" android:layout_centerHorizontal="true" android:background="#374552" /> <ImageView android:id="@+id/iv_weather_state" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerInParent="true" android:background="@mipmap/icon_100" /> </RelativeLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <!--天气状况文字描述--> <TextView android:id="@+id/tv_weather_state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="晴" android:textColor="#FFF" android:textSize="@dimen/sp_16" /> <!--温度--> <TextView android:id="@+id/tv_temperature" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="25℃" android:textColor="#FFF" android:textSize="@dimen/sp_16" /> </LinearLayout> <!--风描述--> <TextView android:gravity="center" android:id="@+id/tv_wind_info" android:layout_width="@dimen/dp_0" android:layout_weight="1" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/dp_16" android:textColor="#FFF" android:textSize="@dimen/sp_14" /> </LinearLayout>
然后写适配器,在adapter包下新建一个HourlyWorldCityAdapter,代码如下:
package com.llw.goodweather.adapter; import android.os.Build; import android.widget.ImageView; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseViewHolder; import com.llw.goodweather.R; import com.llw.goodweather.bean.HourlyResponse; import com.llw.goodweather.utils.DateUtils; import com.llw.goodweather.utils.WeatherUtil; import java.util.List; /** * V7 API 热门城市 逐小时预报数据列表适配器 */ public class HourlyWorldCityAdapter extends BaseQuickAdapter<HourlyResponse.HourlyBean, BaseViewHolder> { public HourlyWorldCityAdapter(int layoutResId, @Nullable List<HourlyResponse.HourlyBean> data) { super(layoutResId, data); } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void convert(BaseViewHolder helper, HourlyResponse.HourlyBean item) { /** * V7 API 涉及到时间的,都会返回 2020-07-16T09:39+08:00 这种格式 * 所以最好写一个通用的返回进行处理 方法已经写好了使用可以了 */ String time = DateUtils.updateTime(item.getFxTime()); helper.setText(R.id.tv_time, WeatherUtil.showTimeInfo(time) + time)//时间 .setText(R.id.tv_temperature, item.getTemp() + "℃") .setText(R.id.tv_weather_state, item.getText()) .setText(R.id.tv_wind_info, item.getWindDir() + "," + item.getWindScale() + "级");//温度 //天气状态图片 ImageView weatherStateIcon = helper.getView(R.id.iv_weather_state); int code = Integer.parseInt(item.getIcon());//获取天气状态码,根据状态码来显示图标 WeatherUtil.changeIcon(weatherStateIcon, code); } }
然后回到WorldCityWeatherActivity中,
@BindView(R.id.tv_title) TextView tvTitle;//城市 @BindView(R.id.toolbar) Toolbar toolbar;//标题bar @BindView(R.id.tv_temperature) TextView tvTemperature;//温度 @BindView(R.id.iv_weather_state) ImageView ivWeatherState;//天气状况图片 @BindView(R.id.tv_tem_max) TextView tvTemMax;//最高温 @BindView(R.id.tv_tem_min) TextView tvTemMin;//最低温 @BindView(R.id.rv_hourly) RecyclerView rvHourly;//逐小时列表 @BindView(R.id.tv_weather_state) TextView tvWeatherState;//天气状态文字描述 @BindView(R.id.tv_wind_state) TextView tvWindState;//风状态文字描述 HourlyWorldCityAdapter mAdapter;//逐小时列表适配器 List<HourlyResponse.HourlyBean> mList = new ArrayList<>();//列表数据
初始化 ,删除掉onCreate方法
@Override public void initData(Bundle savedInstanceState) { initView(); }
/** * 初始化页面 */ private void initView() { StatusBarUtil.transparencyBar(context);//设置状态栏背景颜色 Back(toolbar); showLoadingDialog();//加载弹窗 mAdapter = new HourlyWorldCityAdapter(R.layout.item_weather_hourly_world_list, mList); rvHourly.setLayoutManager(new LinearLayoutManager(context)); rvHourly.setAdapter(mAdapter); String locationId = getIntent().getStringExtra("locationId");//获取上一个页面传递过来的城市id tvTitle.setText(getIntent().getStringExtra("name"));//城市名称显示 mPresent.nowWeather(locationId);//查询实况天气 mPresent.dailyWeather(locationId);//查询天气预报 mPresent.hourlyWeather(locationId);//查询逐小时天气预报 }
@Override public int getLayoutId() { return R.layout.activity_world_city_weather; } @Override protected WorldCityWeatherContract.WorldCityWeatherPresenter createPresent() { return new WorldCityWeatherContract.WorldCityWeatherPresenter(); }
接口返回处理和异常返回处理
/** * 实况天气返回 V7 * * @param response */ @Override public void getNowResult(Response<NowResponse> response) { if (response.body().getCode().equals(Constant.SUCCESS_CODE)) { Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/GenJyuuGothic-ExtraLight.ttf"); tvTemperature.setText(response.body().getNow().getTemp() + "°"); tvTemperature.setTypeface(typeface);//使用字体 int code = Integer.parseInt(response.body().getNow().getIcon());//获取天气状态码,根据状态码来显示图标 WeatherUtil.changeIcon(ivWeatherState, code);//调用工具类中写好的方法 tvWeatherState.setText("当前:" + response.body().getNow().getText()); tvWindState.setText(response.body().getNow().getWindDir()+" "+response.body().getNow().getWindScale()+"级"); } else { ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode())); } } /** * 天气预报 V7 * * @param response */ @Override public void getDailyResult(Response<DailyResponse> response) { if (response.body().getCode().equals(Constant.SUCCESS_CODE)) { if (response.body().getDaily() != null && response.body().getDaily().size() > 0) { tvTemMax.setText(response.body().getDaily().get(0).getTempMax()); tvTemMin.setText(" / " + response.body().getDaily().get(0).getTempMin()); } else { ToastUtils.showShortToast(context, "暂无天气预报数据"); } } else { ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode())); } } /** * 逐小时天气预报 V7 * * @param response */ @Override public void getHourlyResult(Response<HourlyResponse> response) { if (response.body().getCode().equals(Constant.SUCCESS_CODE)) { List<HourlyResponse.HourlyBean> data = response.body().getHourly(); if (data != null && data.size() > 0) { mList.clear(); mList.addAll(data); mAdapter.notifyDataSetChanged(); dismissLoadingDialog(); } else { ToastUtils.showShortToast(context, "逐小时天气查询不到"); } } else { ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getCode())); } } //异常返回 @Override public void getDataFailed() { dismissLoadingDialog(); ToastUtils.showShortToast(context, "请求超时"); }
还差最后一步,修改window_add.xml
回到MainActivity
修改热门城市为世界城市,id也改了。