上一篇:Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整
添加管理城市
新版-------------------
在上一篇文章中添加了天气预报和逐小时天气预报详情数据的显示,是通过底部弹窗的方式管理的,本篇文章中将对城市数据进行一个管理,这里就不同于旧版本的处理方式。
一、添加管理城市页面
首先在ui包下新建一个ManageCityActivity,对应的布局是activity_manage_city.xml,然后检查一下AndroidManifest.xml中的是否正常将此Activity注册进去。
下面我们需要给一个入口,可以从MainActivity中进入到ManageCityActivity,还是添加到菜单里,修改menu_main.xml,在里面添加代码如下所示:
<item
android:id="@+id/item_manage_city"
android:title="管理城市" />
下面我们完善菜单item的点击监听,回到MainActivity中。在onOptionsItemSelected()方法中增加一个case,如下图所示:
点击之后就跳转到ManageCityActivity页面。
二、沉浸式
管理城市页面的效果我打算做成白色风格的,所以状态栏的文字和图标需要变成深色的,那么为了这么做,我们需要改一下主题中的设置,打开values下的themes.xml,将里面的GoodWeatherNew主题改动成如下图所示的样子。
你只需要对照自己的去改就行了,记得也把values-night下的theme.xml一样改动一下,下面我们在BaseActivity中增加一个方法,代码如下:
protected void setStatusBar(boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowInsetsController controller = getWindow().getInsetsController();
controller.setSystemBarsAppearance(dark ? WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
controller.setSystemBarsAppearance(dark ? WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS : 0,
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS);
} else {
getWindow().getDecorView().setSystemUiVisibility(dark ?
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR :
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
这里主要就是设置状态栏的文字和图标颜色,在Android11及以上版本中弃用了setSystemUiVisibility
,所以这里做了一下适配。
三、编写管理城市页面
在后面的编码中会使用到一些图标和颜色,这里我先写出来,在colors.xml中新增如下代码:
<color name="bg_color">#F8F8F8</color><!--页面背景颜色-->
<color name="btn_ripple_color">#B5B3B3</color><!--按钮触摸颜色-->
<color name="card_ripple_color">#A8C0EC</color><!--卡片视图触摸颜色-->
在drawable下新建一个ic_round_add_24.xml,代码如下所示:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,13h-5v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-5H6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h5V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5h5c0.55,0 1,0.45 1,1s-0.45,1 -1,1z" />
</vector>
这里添加的图标,在drawable下新建一个ic_round_arrow_back_24.xml,代码如下所示:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z" />
</vector>
这是页面返回的图标,在drawable下新建一个ic_round_location_on_24.xml,代码如下所示:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2c-4.2,0 -8,3.22 -8,8.2c0,3.18 2.45,6.92 7.34,11.23c0.38,0.33 0.95,0.33 1.33,0C17.55,17.12 20,13.38 20,10.2C20,5.22 16.2,2 12,2zM12,12c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2c1.1,0 2,0.9 2,2C14,11.1 13.1,12 12,12z" />
</vector>
这里定位的图标,和MainActivity中所用不是同一个。下面我们修改activity_manage_city.xml,代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_color"
android:fitsSystemWindows="true"
tools:context=".ui.ManageCityActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/white"
android:elevation="@dimen/dp_4"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_round_arrow_back_24"
app:title="管理城市" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_city"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@+id/btn_add_city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_add_city"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:insetTop="@dimen/dp_0"
android:insetBottom="@dimen/dp_0"
android:text="添加城市"
android:textColor="@color/black"
android:textSize="@dimen/sp_12"
app:icon="@drawable/ic_round_add_32"
app:iconGravity="top"
app:iconPadding="@dimen/dp_0"
app:iconTint="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:rippleColor="@color/btn_ripple_color" />
</androidx.constraintlayout.widget.ConstraintLayout>
xml内容是比较简单的,但是细节很多,要注意一下,下面回到ManageCityActivity,修改代码如下所示:
public class ManageCityActivity extends NetworkActivity<ActivityManageCityBinding> {
@Override
protected void onCreate() {
initView();
}
private void initView() {
backAndFinish(binding.toolbar);
setStatusBar(true);
binding.btnAddCity.setOnClickListener(v -> showMsg("添加城市"));
}
@Override
protected void onObserveData() {
}
}
这里的代码就很简单了,就是页面返回,沉浸式,按钮的监听,现在可以从MainActivity中跳转过来,也能点击返回之前的页面,运行看看效果。
四、城市数据管理
现在页面写好了,那么数据从哪里来呢?我们定位的城市也要添加进来,这样的话,我们在数据库中再增加一个表,并且这个表里面只需要一个城市名称的字段,当有重名的城市就直接替换掉。
在bean包下新建一个MyCity类,里面代码如下所示:
@Entity
public class MyCity {
@NonNull
@PrimaryKey
private String cityName;
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
@Ignore
public MyCity(String cityName) {
this.cityName = cityName;
}
public MyCity() {}
}
这个内容就比较简单了,我们将城市名作为主键,因为是String类型,所以不能为空了,多加了一个@NonNull
注解,下面写方法接口,在dao包下新建一个MyCityDao接口,代码如下:
@Dao
public interface MyCityDao {
/**
* 查询所有城市
*/
@Query("SELECT * FROM MyCity")
Flowable<List<MyCity>> getAllCity();
/**
* 添加城市
*
* @param myCity 城市
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
Completable insertCity(MyCity myCity);
/**
* 通过城市对象删除城市
*
* @param myCity 城市
*/
@Delete
Completable deleteCity(MyCity myCity);
/**
* 通过城市名称删除数据
*
* @param cityName 城市名称
*/
@Query("DELETE FROM MyCity where cityName=:cityName")
Completable deleteCity(String cityName);
}
这里有增加、删除、查询的方法,下面就是回到AppDatabase中,对数据库的表进行增加,同时升级数据库版本,如下图所示:
然后增加抽象方法,代码如下所示:
public abstract MyCityDao myCityDao();
最后进行版本迁移,因为我们进行了数据库的升级,那么这个升级过程你做了什么你需要说清楚,就有一个迁移说明,在AppDatabase中添加如下代码:
/**
* 版本升级迁移到2 新增我的城市表
*/
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `myCity` " +
"(cityName TEXT NOT NULL, " +
"PRIMARY KEY(`cityName`))");
}
};
这个迁移是Room数据库的要求,你可以去官网中了解学习,然后我们将这个迁移添加了数据库的构建过程中,如下图所示:
因为Room用到了编译时技术,所以你可以在编译工程之前先Clean一下,现在数据表有了,下面我们应该写出对应的使用方法,在CityRepository中增加如下代码:
/**
* 获取我的城市所有数据
*/
public void getMyCityData(MutableLiveData<List<MyCity>> listMutableLiveData) {
CustomDisposable.addDisposable(WeatherApp.getDb().myCityDao().getAllCity(), listMutableLiveData::postValue);
}
/**
* 添加我的城市数据
*/
public void addMyCityData(MyCity myCity) {
CustomDisposable.addDisposable(WeatherApp.getDb().myCityDao().insertCity(myCity), () -> Log.d(TAG, "addMyCityData: 插入数据成功。"));
}
/**
* 删除我的城市数据
*/
public void deleteMyCityData(String cityName) {
CustomDisposable.addDisposable(WeatherApp.getDb().myCityDao().deleteCity(cityName), () -> Log.d(TAG, "deleteMyCityData: 删除数据成功"));
}
/**
* 删除我的城市数据
*/
public void deleteMyCityData(MyCity myCity) {
CustomDisposable.addDisposable(WeatherApp.getDb().myCityDao().deleteCity(myCity), () -> Log.d(TAG, "deleteMyCityData: 删除数据成功"));
}
然后就是调用的地方,如果我们需要在MainActivity中保存定位城市,那么就需要在MainViewModel中添加一个方法,代码如下所示:
/**
* 添加我的城市数据,在定位之后添加数据
*/
public void addMyCityData(String cityName) {
MyCity myCity = new MyCity(cityName);
CityRepository.getInstance().addMyCityData(myCity);
}
最后我们在MainActivity中使用这个MainViewModel中的方法,在使用之前我们还要思考一个问题,那就是,如果我们的管理城市页面有很多城市,里有通过定位拿到的城市,也有通过其他方式拿到的城市,那么怎么知道当前是定位的城市是哪一个呢?
可以写一个常量值来保存,在Constant中新增如下代码:
/**
* 当前定位城市
*/
public static final String LOCATION_CITY = "locationCity";
/**
* 页面返回城市结果
*/
public static final String CITY_RESULT = "cityResult";
一个用来记录当前定位的城市,另一个值回到页面返回的时候用到的,下面就是在定位回调中先记录当前的城市,然后再保存到数据库中,修改onReceiveLocation()方法,如下图所示:
现在只要你一运行,获取定位城市之后就会保存到数据库中,如果表中数据城市名称重复就会替换,那么我们还需要在管理城市页面的列表中看到所添加的城市数据。
五、显示我的城市数据
下面我们先创建item的布局,在layout下新建一个item_my_city_rv.xml,代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_4"
android:layout_marginEnd="@dimen/dp_8"
android:layout_marginBottom="@dimen/dp_4"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
app:cardCornerRadius="@dimen/dp_16"
app:cardElevation="@dimen/dp_8"
app:rippleColor="@color/card_ripple_color"
app:state_dragged="true">
<!--城市名称-->
<TextView
android:id="@+id/tv_city_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/dp_16"
android:text="城市名称"
android:textColor="@color/black"
android:textSize="@dimen/sp_16"
tools:ignore="RtlSymmetry" />
<!--是否定位-->
<ImageView
android:id="@+id/iv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="@dimen/dp_16"
android:src="@drawable/ic_round_location_on_24"
android:visibility="invisible" />
</com.google.android.material.card.MaterialCardView>
这里就是一个卡片视图,点击了也有水波纹效果,下面创建适配器,在adapter包下新建一个MyCityAdapter类,代码如下所示:
public class MyCityAdapter extends RecyclerView.Adapter<MyCityAdapter.ViewHolder> {
private final List<MyCity> cities;
private OnClickItemCallback onClickItemCallback;//视图点击
public MyCityAdapter(List<MyCity> cities) {
this.cities = cities;
}
public void setOnClickItemCallback(OnClickItemCallback onClickItemCallback) {
this.onClickItemCallback = onClickItemCallback;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemMyCityRvBinding binding = ItemMyCityRvBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
ViewHolder viewHolder = new ViewHolder(binding);
//添加视图点击事件
binding.getRoot().setOnClickListener(v -> {
if (onClickItemCallback != null) {
onClickItemCallback.onItemClick(viewHolder.getAdapterPosition());
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String cityName = cities.get(position).getCityName();
String locationCity = MVUtils.getString(Constant.LOCATION_CITY);
holder.binding.tvCityName.setText(cityName);
holder.binding.ivLocation.setVisibility(cityName.equals(locationCity) ? View.VISIBLE : View.GONE);
}
@Override
public int getItemCount() {
return cities.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ItemMyCityRvBinding binding;
public ViewHolder(@NonNull ItemMyCityRvBinding itemMyCityRvBinding) {
super(itemMyCityRvBinding.getRoot());
binding = itemMyCityRvBinding;
}
}
}
这个适配器中大部分代码你都见过了,注意里面有一个当前城市是否为定位城市的判断,是就会显示定位图标。现在适配器也有了,下面就是在ManageCityActivity请求数据,然后渲染了,那么我们相应的就需要在viewmodel包下新建一个ManageCityViewModel类,里面的代码如下所示:
public class ManageCityViewModel extends BaseViewModel {
public MutableLiveData<List<MyCity>> listMutableLiveData = new MutableLiveData<>();
/**
* 获取所有城市数据
*/
public void getAllCityData() {
CityRepository.getInstance().getMyCityData(listMutableLiveData);
}
}
下面回到ManageCityActivity中,修改代码如下所示:
public class ManageCityActivity extends NetworkActivity<ActivityManageCityBinding> {
private ManageCityViewModel viewModel;
private final List<MyCity> myCityList = new ArrayList<>();
private final MyCityAdapter myCityAdapter = new MyCityAdapter(myCityList);
@Override
protected void onCreate() {
initView();
viewModel = new ViewModelProvider(this).get(ManageCityViewModel.class);
viewModel.getAllCityData();
}
private void initView() {
backAndFinish(binding.toolbar);
setStatusBar(true);
myCityAdapter.setOnClickItemCallback(position -> {
showMsg(myCityList.get(position).getCityName());
});
binding.rvCity.setLayoutManager(new LinearLayoutManager(ManageCityActivity.this));
binding.rvCity.setAdapter(myCityAdapter);
binding.btnAddCity.setOnClickListener(v -> showMsg("添加城市"));
}
@SuppressLint("NotifyDataSetChanged")
@Override
protected void onObserveData() {
viewModel.listMutableLiveData.observe(this, myCities -> {
if (myCities != null && myCities.size() > 0) {
myCityList.clear();
myCityList.addAll(myCities);
myCityAdapter.notifyDataSetChanged();
} else {
showMsg("空空如也");
}
});
}
}
现在可以再运行一下了。
六、返回城市结果
现在数据也有了,点击之后怎么让MainActivity知晓,然后去进行城市的搜索呢,我们可以在点击item时将结果返回给MainActivity,因此我们MainActivity中跳转ManageCityActivity的方式要改动一下,在MainActivity中新增变量:
private ActivityResultLauncher<Intent> jumpActivityIntent;
在onRegister()方法中,增加如下代码:
jumpActivityIntent = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
//获取上个页面返回的数据
String city = result.getData().getStringExtra(Constant.CITY_RESULT);
//检查返回的城市 , 如果返回的城市是当前定位城市,并且当前定位标志为0,则不需要请求
if (city.equals(MVUtils.getString(Constant.LOCATION_CITY)) && cityFlag == 0) {
Log.d("TAG", "onRegister: 管理城市页面返回不需要进行天气查询");
return;
}
//反之就直接调用选中城市的方法进行城市天气搜索
Log.d("TAG", "onRegister: 管理城市页面返回进行天气查询");
selectedCity(city);
}
});
这里的代码就是对页面返回传递的值进行判断处理,通过注释你应该能看明白是什么意思,下面修改之前的跳转方式,如下图所示:
再回到ManageCityActivity,修改适配器点击时的处理,代码如下所示:
myCityAdapter.setOnClickItemCallback(position -> {
Intent intent = new Intent();
intent.putExtra(Constant.CITY_RESULT, myCityList.get(position).getCityName());
setResult(Activity.RESULT_OK, intent);
finish();
});
下面再运行一下,进入管理城市页面,点击Item返回,查看控制台,看到当点击Item的时候将值传递给了MainActivity,这里的日志打印就说明了这一点。
现在只是定位城市的添加,下一篇会做添加城市。
七、文章源码
欢迎 Star 和 Fork
第十四篇文章源码地址: GoodWeather-New-14
旧版-------------------
完成此篇文章之后的运行效果图
前言
在上一篇文章中增加了自定义背景的功能的同时也遗留了一些问题,为阅读者带来的不便,敬请谅解,在这一篇中将会优化这些问题,同时优化业务逻辑代码,做到用最少的代码量办最多的事情,同时对UI的用户体验进一步提升,增加天气详情数据的显示。
正文
首先是修复之前问题吧,这个问题我本身是知道的,不过因为工作时间的原因,近期就没有来得及改这个问题,但我又不想在原来的第十三篇文章中进行修正,因为有问题很正常,正视这个问题并解决就好了,这个问题说起来也比较的简单,就是Actvity的生命周期没有处理好造成了数据异常提示。
首先在MainActivity.java中的
private boolean flagOther = false;//跳转其他页面时才为true
然后在Constant.java中增加一个Key
public final static String FLAG_OTHER_RETURN="flag_other_return";//跳转页面的标识
回到MainActivity.java中,Ctrl + F 搜索当前页面,在搜索输入框输入changeBg.setOnClickListener,改动如下图所示。
改完了这里,再搜索onResume,改动如下图所示:
这个代码逻辑是这样的
在Activity的生命周期中,一个Activity的执行过程是onCreate→onStart→onResume,如果这个时候你跳转到另一个页面,那么当前页面将执行onPause→onStop,而新页面将会执行onCreate→onStart→onResume,如果这个时候我们通过返回键返回到之前的页面,新页面会执行onPause→onStop,之前的页面会执行onRestart→onStart→onResume。通过这个操作你是不是明白我为什么要在onResume方法里面做逻辑处理了呢。首先一进来这个页面就会执行onResume方法,这个时候我取缓存的值来判断,但是缓存中没有值的话就是默认的false,而false则不会执行里面的方法,但当我跳转到切换背景页面时,这个缓存中已经赋值为true,这时不管我有没有设置背景模式,缓存中都会有值,而另一个页面返回到之前页面也会执行onResume方法,这时,就为true了,所以就会执行里面的业务逻辑代码,不知道你理解了没有。
问题修复之后,优化提示文本,在app的utils包下创建一个CodeToStringUtils工具类
代码如下:
package com.llw.goodweather.utils;
public class CodeToStringUtils {
public static String WeatherCode(String code){
String codeInfo = null;
switch (code){
case "ok":
codeInfo = "正常";
break;
case "invalid key":
codeInfo = "无效的key";
break;
case "invalid key type":
codeInfo = "你输入的key不适用于当前获取数据的方式,即SDK的KEY不能用于Web API或通过接口直接访问,反之亦然。";
break;
case "invalid param":
codeInfo = "无效的参数,请检查你传递的参数是否正确、完整";
break;
case "bad bind":
codeInfo = "错误的绑定,例如绑定的package name、bundle id或IP地址不一致的时候";
break;
case "no data for this location":
codeInfo = "该城市/地区没有你所请求的数据";
break;
case "no more requests":
codeInfo = "超过访问次数,需要等到当月最后一天24点(免费用户为当天24点)后进行访问次数的重置或升级你的访问量";
break;
case "no balance":
codeInfo = "没有余额,你的按量计费产品由于余额不足或欠费而不能访问,请尽快充值";
break;
case "too fast":
codeInfo = "超过限定的QPM";
break;
case "dead":
codeInfo = "无响应或超时";
break;
case "unknown location":
codeInfo = "没有你查询的这个地区,或者地区名称错误";
break;
case "permission denied":
codeInfo = "无访问权限,你没有购买你所访问的这部分服务";
break;
case "sign error":
codeInfo = "签名错误";
break;
}
return codeInfo;
}
}
这里就是根据和风API的返回码匹配上中文提示,因为用户那里知道你的英文是什么意思呢?所以这样会比较好一些,接下来就是使用这个了。
这里我就是举个例子,有好几个方法,你可以全部都改了。
优化代码
优化代码,无非就是精简,怎么精简呢,首先从接口上来看怎么精简。我们现在一共是用了两个接口,一个是和风天气的、一个是必应每日一图的。而和风天气的接口下面有五个子接口,其中前四个是一个分支接口下来的,也就是weather,后一个是在air下的空气质量,这一个空气质量,免费的就只有当前的空气质量,但是前一个weather接口的返回数据是我们根据不同的类型去改变url地址得到的数据,既然都在weather下,是否能够四合一呢?写一个就搞定呢?这样代码量会不会少很多呢?
带着这些思考去实践一下。
实践之前,我先给生活指数加上一个紫外线的数据返回显示,首先修改activity_main.xml文件
在舒适度的上方加一个显示紫外线的,深圳的紫外线太强了,讲真的。然后修改MainActivity.xml
这里我把原来的if判断改为了switch这样看起来更清晰一些,不容易出错,但是用switch要记得break;
switch (data.get(i).getType()){
case "uv":
tvUv.setText("紫外线:" + data.get(i).getTxt());
break;
case "comf":
tvComf.setText("舒适度:" + data.get(i).getTxt());
break;
case "drsg":
tvDrsg.setText("穿衣指数:" + data.get(i).getTxt());
break;
case "flu":
tvFlu.setText("感冒指数:" + data.get(i).getTxt());
break;
case "sport":
tvSport.setText("运动指数:" + data.get(i).getTxt());
break;
case "trav":
tvTrav.setText("旅游指数:" + data.get(i).getTxt());
break;
case "cw":
tvCw.setText("洗车指数:" + data.get(i).getTxt());
break;
case "air":
tvAir.setText("空气指数:" + data.get(i).getTxt());
break;
}
现在去合并接口吧。
合并之前需要一个访问地址。
https://free-api.heweather.net/s6/weather?key=3086e91d66c04ce588a7f538f917c7f4&location=深圳
拿到返回值,生成实体bean
代码如下:
package com.llw.goodweather.bean;
import java.util.List;
public class WeatherResponse {
private List<HeWeather6Bean> HeWeather6;
public List<HeWeather6Bean> getHeWeather6() {
return HeWeather6;
}
public void setHeWeather6(List<HeWeather6Bean> HeWeather6) {
this.HeWeather6 = HeWeather6;
}
public static class HeWeather6Bean {
/**
* basic : {"cid":"CN101280601","location":"深圳","parent_city":"深圳","admin_area":"广东","cnty":"中国","lat":"22.54700089","lon":"114.08594513","tz":"+8.00"}
* update : {"loc":"2020-05-16 10:03","utc":"2020-05-16 02:03"}
* status : ok
* now : {"cloud":"10","cond_code":"100","cond_txt":"晴","fl":"33","hum":"74","pcpn":"0.0","pres":"1001","tmp":"29","vis":"16","wind_deg":"227","wind_dir":"西南风","wind_sc":"1","wind_spd":"2"}
* daily_forecast : [{"cond_code_d":"101","cond_code_n":"104","cond_txt_d":"多云","cond_txt_n":"阴","date":"2020-05-16","hum":"83","mr":"01:57","ms":"13:36","pcpn":"0.0","pop":"4","pres":"998","sr":"05:42","ss":"18:57","tmp_max":"34","tmp_min":"24","uv_index":"9","vis":"25","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"6"},{"cond_code_d":"302","cond_code_n":"306","cond_txt_d":"雷阵雨","cond_txt_n":"中雨","date":"2020-05-17","hum":"83","mr":"02:31","ms":"14:26","pcpn":"0.0","pop":"25","pres":"995","sr":"05:42","ss":"18:58","tmp_max":"33","tmp_min":"25","uv_index":"1","vis":"15","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"11"},{"cond_code_d":"306","cond_code_n":"307","cond_txt_d":"中雨","cond_txt_n":"大雨","date":"2020-05-18","hum":"88","mr":"03:04","ms":"15:15","pcpn":"5.1","pop":"80","pres":"996","sr":"05:41","ss":"18:58","tmp_max":"28","tmp_min":"24","uv_index":"2","vis":"22","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"6"},{"cond_code_d":"306","cond_code_n":"300","cond_txt_d":"中雨","cond_txt_n":"阵雨","date":"2020-05-19","hum":"78","mr":"03:37","ms":"16:04","pcpn":"6.1","pop":"68","pres":"997","sr":"05:41","ss":"18:59","tmp_max":"30","tmp_min":"26","uv_index":"0","vis":"22","wind_deg":"234","wind_dir":"西南风","wind_sc":"3-4","wind_spd":"15"},{"cond_code_d":"300","cond_code_n":"316","cond_txt_d":"阵雨","cond_txt_n":"大到暴雨","date":"2020-05-20","hum":"81","mr":"04:09","ms":"16:53","pcpn":"0.0","pop":"25","pres":"997","sr":"05:41","ss":"18:59","tmp_max":"31","tmp_min":"25","uv_index":"10","vis":"22","wind_deg":"234","wind_dir":"西南风","wind_sc":"3-4","wind_spd":"20"},{"cond_code_d":"316","cond_code_n":"316","cond_txt_d":"大到暴雨","cond_txt_n":"大到暴雨","date":"2020-05-21","hum":"81","mr":"04:42","ms":"17:45","pcpn":"5.1","pop":"80","pres":"994","sr":"05:40","ss":"19:00","tmp_max":"30","tmp_min":"25","uv_index":"3","vis":"13","wind_deg":"226","wind_dir":"西南风","wind_sc":"3-4","wind_spd":"20"},{"cond_code_d":"306","cond_code_n":"310","cond_txt_d":"中雨","cond_txt_n":"暴雨","date":"2020-05-22","hum":"86","mr":"05:19","ms":"18:37","pcpn":"6.1","pop":"68","pres":"996","sr":"05:40","ss":"19:00","tmp_max":"31","tmp_min":"27","uv_index":"5","vis":"8","wind_deg":"244","wind_dir":"西南风","wind_sc":"3-4","wind_spd":"23"}]
* hourly : [{"cloud":"11","cond_code":"101","cond_txt":"多云","dew":"22","hum":"73","pop":"7","pres":"998","time":"2020-05-16 13:00","tmp":"33","wind_deg":"174","wind_dir":"南风","wind_sc":"1-2","wind_spd":"5"},{"cloud":"9","cond_code":"101","cond_txt":"多云","dew":"22","hum":"73","pop":"7","pres":"999","time":"2020-05-16 16:00","tmp":"33","wind_deg":"188","wind_dir":"南风","wind_sc":"1-2","wind_spd":"2"},{"cloud":"19","cond_code":"101","cond_txt":"多云","dew":"24","hum":"81","pop":"0","pres":"997","time":"2020-05-16 19:00","tmp":"29","wind_deg":"170","wind_dir":"南风","wind_sc":"1-2","wind_spd":"11"},{"cloud":"74","cond_code":"101","cond_txt":"多云","dew":"25","hum":"85","pop":"0","pres":"998","time":"2020-05-16 22:00","tmp":"25","wind_deg":"181","wind_dir":"南风","wind_sc":"1-2","wind_spd":"3"},{"cloud":"68","cond_code":"104","cond_txt":"阴","dew":"24","hum":"85","pop":"0","pres":"999","time":"2020-05-17 01:00","tmp":"25","wind_deg":"187","wind_dir":"南风","wind_sc":"1-2","wind_spd":"9"},{"cloud":"70","cond_code":"104","cond_txt":"阴","dew":"25","hum":"84","pop":"0","pres":"998","time":"2020-05-17 04:00","tmp":"24","wind_deg":"182","wind_dir":"南风","wind_sc":"1-2","wind_spd":"11"},{"cloud":"65","cond_code":"104","cond_txt":"阴","dew":"26","hum":"84","pop":"43","pres":"996","time":"2020-05-17 07:00","tmp":"26","wind_deg":"188","wind_dir":"南风","wind_sc":"1-2","wind_spd":"1"},{"cloud":"52","cond_code":"104","cond_txt":"阴","dew":"23","hum":"77","pop":"46","pres":"995","time":"2020-05-17 10:00","tmp":"31","wind_deg":"-1","wind_dir":"无持续风向","wind_sc":"1-2","wind_spd":"8"}]
* lifestyle : [{"type":"comf","brf":"较不舒适","txt":"白天天气多云,并且空气湿度偏大,在这种天气条件下,您会感到有些闷热,不很舒适。"},{"type":"drsg","brf":"炎热","txt":"天气炎热,建议着短衫、短裙、短裤、薄型T恤衫等清凉夏季服装。"},{"type":"flu","brf":"少发","txt":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。"},{"type":"sport","brf":"较不宜","txt":"天气较好,无雨水困扰,但考虑气温很高,请注意适当减少运动时间并降低运动强度,运动后及时补充水分。"},{"type":"trav","brf":"较适宜","txt":"天气较好,温度较高,天气较热,但有微风相伴,还是比较适宜旅游的,不过外出时要注意防暑防晒哦!"},{"type":"uv","brf":"强","txt":"紫外线辐射强,建议涂擦SPF20左右、PA++的防晒护肤品。避免在10点至14点暴露于日光下。"},{"type":"cw","brf":"较适宜","txt":"较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。"},{"type":"air","brf":"中","txt":"气象条件对空气污染物稀释、扩散和清除无明显影响。"}]
*/
private BasicBean basic;
private UpdateBean update;
private String status;
private NowBean now;
private List<DailyForecastBean> daily_forecast;
private List<HourlyBean> hourly;
private List<LifestyleBean> lifestyle;
public BasicBean getBasic() {
return basic;
}
public void setBasic(BasicBean basic) {
this.basic = basic;
}
public UpdateBean getUpdate() {
return update;
}
public void setUpdate(UpdateBean update) {
this.update = update;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public NowBean getNow() {
return now;
}
public void setNow(NowBean now) {
this.now = now;
}
public List<DailyForecastBean> getDaily_forecast() {
return daily_forecast;
}
public void setDaily_forecast(List<DailyForecastBean> daily_forecast) {
this.daily_forecast = daily_forecast;
}
public List<HourlyBean> getHourly() {
return hourly;
}
public void setHourly(List<HourlyBean> hourly) {
this.hourly = hourly;
}
public List<LifestyleBean> getLifestyle() {
return lifestyle;
}
public void setLifestyle(List<LifestyleBean> lifestyle) {
this.lifestyle = lifestyle;
}
public static class BasicBean {
/**
* cid : CN101280601
* location : 深圳
* parent_city : 深圳
* admin_area : 广东
* cnty : 中国
* lat : 22.54700089
* lon : 114.08594513
* tz : +8.00
*/
private String cid;
private String location;
private String parent_city;
private String admin_area;
private String cnty;
private String lat;
private String lon;
private String tz;
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getParent_city() {
return parent_city;
}
public void setParent_city(String parent_city) {
this.parent_city = parent_city;
}
public String getAdmin_area() {
return admin_area;
}
public void setAdmin_area(String admin_area) {
this.admin_area = admin_area;
}
public String getCnty() {
return cnty;
}
public void setCnty(String cnty) {
this.cnty = cnty;
}
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getLon() {
return lon;
}
public void setLon(String lon) {
this.lon = lon;
}
public String getTz() {
return tz;
}
public void setTz(String tz) {
this.tz = tz;
}
}
public static class UpdateBean {
/**
* loc : 2020-05-16 10:03
* utc : 2020-05-16 02:03
*/
private String loc;
private String utc;
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public String getUtc() {
return utc;
}
public void setUtc(String utc) {
this.utc = utc;
}
}
public static class NowBean {
/**
* cloud : 10
* cond_code : 100
* cond_txt : 晴
* fl : 33
* hum : 74
* pcpn : 0.0
* pres : 1001
* tmp : 29
* vis : 16
* wind_deg : 227
* wind_dir : 西南风
* wind_sc : 1
* wind_spd : 2
*/
private String cloud;
private String cond_code;
private String cond_txt;
private String fl;
private String hum;
private String pcpn;
private String pres;
private String tmp;
private String vis;
private String wind_deg;
private String wind_dir;
private String wind_sc;
private String wind_spd;
public String getCloud() {
return cloud;
}
public void setCloud(String cloud) {
this.cloud = cloud;
}
public String getCond_code() {
return cond_code;
}
public void setCond_code(String cond_code) {
this.cond_code = cond_code;
}
public String getCond_txt() {
return cond_txt;
}
public void setCond_txt(String cond_txt) {
this.cond_txt = cond_txt;
}
public String getFl() {
return fl;
}
public void setFl(String fl) {
this.fl = fl;
}
public String getHum() {
return hum;
}
public void setHum(String hum) {
this.hum = hum;
}
public String getPcpn() {
return pcpn;
}
public void setPcpn(String pcpn) {
this.pcpn = pcpn;
}
public String getPres() {
return pres;
}
public void setPres(String pres) {
this.pres = pres;
}
public String getTmp() {
return tmp;
}
public void setTmp(String tmp) {
this.tmp = tmp;
}
public String getVis() {
return vis;
}
public void setVis(String vis) {
this.vis = vis;
}
public String getWind_deg() {
return wind_deg;
}
public void setWind_deg(String wind_deg) {
this.wind_deg = wind_deg;
}
public String getWind_dir() {
return wind_dir;
}
public void setWind_dir(String wind_dir) {
this.wind_dir = wind_dir;
}
public String getWind_sc() {
return wind_sc;
}
public void setWind_sc(String wind_sc) {
this.wind_sc = wind_sc;
}
public String getWind_spd() {
return wind_spd;
}
public void setWind_spd(String wind_spd) {
this.wind_spd = wind_spd;
}
}
public static class DailyForecastBean {
/**
* cond_code_d : 101
* cond_code_n : 104
* cond_txt_d : 多云
* cond_txt_n : 阴
* date : 2020-05-16
* hum : 83
* mr : 01:57
* ms : 13:36
* pcpn : 0.0
* pop : 4
* pres : 998
* sr : 05:42
* ss : 18:57
* tmp_max : 34
* tmp_min : 24
* uv_index : 9
* vis : 25
* wind_deg : -1
* wind_dir : 无持续风向
* wind_sc : 1-2
* wind_spd : 6
*/
private String cond_code_d;
private String cond_code_n;
private String cond_txt_d;
private String cond_txt_n;
private String date;
private String hum;
private String mr;
private String ms;
private String pcpn;
private String pop;
private String pres;
private String sr;
private String ss;
private String tmp_max;
private String tmp_min;
private String uv_index;
private String vis;
private String wind_deg;
private String wind_dir;
private String wind_sc;
private String wind_spd;
public String getCond_code_d() {
return cond_code_d;
}
public void setCond_code_d(String cond_code_d) {
this.cond_code_d = cond_code_d;
}
public String getCond_code_n() {
return cond_code_n;
}
public void setCond_code_n(String cond_code_n) {
this.cond_code_n = cond_code_n;
}
public String getCond_txt_d() {
return cond_txt_d;
}
public void setCond_txt_d(String cond_txt_d) {
this.cond_txt_d = cond_txt_d;
}
public String getCond_txt_n() {
return cond_txt_n;
}
public void setCond_txt_n(String cond_txt_n) {
this.cond_txt_n = cond_txt_n;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getHum() {
return hum;
}
public void setHum(String hum) {
this.hum = hum;
}
public String getMr() {
return mr;
}
public void setMr(String mr) {
this.mr = mr;
}
public String getMs() {
return ms;
}
public void setMs(String ms) {
this.ms = ms;
}
public String getPcpn() {
return pcpn;
}
public void setPcpn(String pcpn) {
this.pcpn = pcpn;
}
public String getPop() {
return pop;
}
public void setPop(String pop) {
this.pop = pop;
}
public String getPres() {
return pres;
}
public void setPres(String pres) {
this.pres = pres;
}
public String getSr() {
return sr;
}
public void setSr(String sr) {
this.sr = sr;
}
public String getSs() {
return ss;
}
public void setSs(String ss) {
this.ss = ss;
}
public String getTmp_max() {
return tmp_max;
}
public void setTmp_max(String tmp_max) {
this.tmp_max = tmp_max;
}
public String getTmp_min() {
return tmp_min;
}
public void setTmp_min(String tmp_min) {
this.tmp_min = tmp_min;
}
public String getUv_index() {
return uv_index;
}
public void setUv_index(String uv_index) {
this.uv_index = uv_index;
}
public String getVis() {
return vis;
}
public void setVis(String vis) {
this.vis = vis;
}
public String getWind_deg() {
return wind_deg;
}
public void setWind_deg(String wind_deg) {
this.wind_deg = wind_deg;
}
public String getWind_dir() {
return wind_dir;
}
public void setWind_dir(String wind_dir) {
this.wind_dir = wind_dir;
}
public String getWind_sc() {
return wind_sc;
}
public void setWind_sc(String wind_sc) {
this.wind_sc = wind_sc;
}
public String getWind_spd() {
return wind_spd;
}
public void setWind_spd(String wind_spd) {
this.wind_spd = wind_spd;
}
}
public static class HourlyBean {
/**
* cloud : 11
* cond_code : 101
* cond_txt : 多云
* dew : 22
* hum : 73
* pop : 7
* pres : 998
* time : 2020-05-16 13:00
* tmp : 33
* wind_deg : 174
* wind_dir : 南风
* wind_sc : 1-2
* wind_spd : 5
*/
private String cloud;
private String cond_code;
private String cond_txt;
private String dew;
private String hum;
private String pop;
private String pres;
private String time;
private String tmp;
private String wind_deg;
private String wind_dir;
private String wind_sc;
private String wind_spd;
public String getCloud() {
return cloud;
}
public void setCloud(String cloud) {
this.cloud = cloud;
}
public String getCond_code() {
return cond_code;
}
public void setCond_code(String cond_code) {
this.cond_code = cond_code;
}
public String getCond_txt() {
return cond_txt;
}
public void setCond_txt(String cond_txt) {
this.cond_txt = cond_txt;
}
public String getDew() {
return dew;
}
public void setDew(String dew) {
this.dew = dew;
}
public String getHum() {
return hum;
}
public void setHum(String hum) {
this.hum = hum;
}
public String getPop() {
return pop;
}
public void setPop(String pop) {
this.pop = pop;
}
public String getPres() {
return pres;
}
public void setPres(String pres) {
this.pres = pres;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getTmp() {
return tmp;
}
public void setTmp(String tmp) {
this.tmp = tmp;
}
public String getWind_deg() {
return wind_deg;
}
public void setWind_deg(String wind_deg) {
this.wind_deg = wind_deg;
}
public String getWind_dir() {
return wind_dir;
}
public void setWind_dir(String wind_dir) {
this.wind_dir = wind_dir;
}
public String getWind_sc() {
return wind_sc;
}
public void setWind_sc(String wind_sc) {
this.wind_sc = wind_sc;
}
public String getWind_spd() {
return wind_spd;
}
public void setWind_spd(String wind_spd) {
this.wind_spd = wind_spd;
}
}
public static class LifestyleBean {
/**
* type : comf
* brf : 较不舒适
* txt : 白天天气多云,并且空气湿度偏大,在这种天气条件下,您会感到有些闷热,不很舒适。
*/
private String type;
private String brf;
private String txt;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBrf() {
return brf;
}
public void setBrf(String brf) {
this.brf = brf;
}
public String getTxt() {
return txt;
}
public void setTxt(String txt) {
this.txt = txt;
}
}
}
}
在ApiService中增加
/**
* 获取所有天气数据,在返回值中再做处理
* @param location
* @return
*/
@GET("/s6/weather?key=3086e91d66c04ce588a7f538f917c7f4")
Call<WeatherResponse> weatherData(@Query("location") String location);
在WeatherContract中增加订阅
/**
* 天气所有数据
* @param context
* @param location
*/
public void weatherData(final Context context,String location){
ApiService service = ServiceGenerator.createService(ApiService.class,0);
service.weatherData(location).enqueue(new NetCallBack<WeatherResponse>() {
@Override
public void onSuccess(Call<WeatherResponse> call, Response<WeatherResponse> response) {
if(getView() != null){
getView().getWeatherDataResult(response);
}
}
@Override
public void onFailed() {
if(getView() != null){
getView().getWeatherDataFailed();
}
}
});
}
//查询天气所有数据
void getWeatherDataResult(Response<WeatherResponse> response);
//天气数据获取错误返回
void getWeatherDataFailed();
进入MainActivity.java中
/**
* 所有天气数据返回
* @param response
*/
@Override
public void getWeatherDataResult(Response<WeatherResponse> response) {
dismissLoadingDialog();//关闭弹窗
if (("ok").equals(response.body().getHeWeather6().get(0).getStatus())) {
}else {
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getHeWeather6().get(0).getStatus()));
}
}
首先改动适配器
七天天气预报适配器WeatherForecastAdapter.java
逐小时天气预报适配器WeatherHourlyAdapter.java
然后回到MainActivity.java
红框中为新增的,然后之前的注释掉,当所有的改动都完成之后,再删除掉注释的没有用的代码、
红框中的就是你要改动的
然后修改切换城市之后的方法请求
定位后
下拉刷新之后
onResume方法中
返回值里面的业务逻辑处理代码先注释掉,最后修改getWeatherDataResult。
修改代码如下:
/**
* 所有天气数据返回
* @param response
*/
@Override
public void getWeatherDataResult(Response<WeatherResponse> response) {
refresh.finishRefresh();//关闭刷新
dismissLoadingDialog();//关闭弹窗
if (mLocationClient != null) {
mLocationClient.stop();//数据返回后关闭定位
}
if (("ok").equals(response.body().getHeWeather6().get(0).getStatus())) {
if (response.body().getHeWeather6().get(0).getBasic() != null) {//得到数据不为空则进行数据显示
/**
* 当天天气
*/
tvTemperature.setText(response.body().getHeWeather6().get(0).getNow().getTmp());//温度
if (flag) {
ivLocation.setVisibility(View.VISIBLE);//显示定位图标
} else {
ivLocation.setVisibility(View.GONE);//显示定位图标
}
tvCity.setText(response.body().getHeWeather6().get(0).getBasic().getLocation());//城市
tvInfo.setText(response.body().getHeWeather6().get(0).getNow().getCond_txt());//天气状况
//修改上次更新时间的结果显示 -> 更加人性化
String datetime = response.body().getHeWeather6().get(0).getUpdate().getLoc();//赋值
String time = datetime.substring(11);//截去前面的字符,保留后面所有的字符,就剩下 22:00
tvOldTime.setText("上次更新时间:" + WeatherUtil.showTimeInfo(time) + time);
tvWindDirection.setText("风向 " + response.body().getHeWeather6().get(0).getNow().getWind_dir());//风向
tvWindPower.setText("风力 " + response.body().getHeWeather6().get(0).getNow().getWind_sc() + "级");//风力
wwBig.startRotate();//大风车开始转动
wwSmall.startRotate();//小风车开始转动
/**
* 查询7天天气预报
*/
//最低温和最高温
tvLowHeight.setText(response.body().getHeWeather6().get(0).getDaily_forecast().get(0).getTmp_min() + " / " +
response.body().getHeWeather6().get(0).getDaily_forecast().get(0).getTmp_max() + "℃");
if (response.body().getHeWeather6().get(0).getDaily_forecast() != null) {
List<WeatherResponse.HeWeather6Bean.DailyForecastBean> data
= response.body().getHeWeather6().get(0).getDaily_forecast();
mListDailyForecast.clear();//添加数据之前先清除
mListDailyForecast.addAll(data);//添加数据
mAdapter.notifyDataSetChanged();//刷新列表
} else {
ToastUtils.showShortToast(context, "天气预报数据为空");
}
/**
* 查询逐小时天气数据
*/
if (response.body().getHeWeather6().get(0).getHourly() != null) {
List<WeatherResponse.HeWeather6Bean.HourlyBean> data
= response.body().getHeWeather6().get(0).getHourly();
mListHourlyBean.clear();//添加数据之前先清除
mListHourlyBean.addAll(data);//添加数据
mAdapterHourly.notifyDataSetChanged();//刷新列表
} else {
ToastUtils.showShortToast(context, "逐小时预报数据为空");
}
/**
* 生活指数
*/
List<WeatherResponse.HeWeather6Bean.LifestyleBean> data = response.body().getHeWeather6().get(0).getLifestyle();
if (!ObjectUtils.isEmpty(data)) {
for (int i = 0; i < data.size(); i++) {
switch (data.get(i).getType()){
case "uv":
tvUv.setText("紫外线:" + data.get(i).getTxt());
break;
case "comf":
tvComf.setText("舒适度:" + data.get(i).getTxt());
break;
case "drsg":
tvDrsg.setText("穿衣指数:" + data.get(i).getTxt());
break;
case "flu":
tvFlu.setText("感冒指数:" + data.get(i).getTxt());
break;
case "sport":
tvSport.setText("运动指数:" + data.get(i).getTxt());
break;
case "trav":
tvTrav.setText("旅游指数:" + data.get(i).getTxt());
break;
case "cw":
tvCw.setText("洗车指数:" + data.get(i).getTxt());
break;
case "air":
tvAir.setText("空气指数:" + data.get(i).getTxt());
break;
}
}
} else {
ToastUtils.showShortToast(context, "生活指数数据为空");
}
}else {
ToastUtils.showShortToast(context,"天气数据为空");
}
}else {
ToastUtils.showShortToast(context, CodeToStringUtils.WeatherCode(response.body().getHeWeather6().get(0).getStatus()));
}
改到这里就是初步改完了,运行一下:
很明显,和之前什么变化都没有,但是,里面的业务处理方式发生了改变,之前是一次性请求四次接口,现在是变成一个接口了,无疑在机制上有了优化,现在就可以注释掉其他的代码了。
打开ApiService
这里将之前的四个API注释掉。
再打开订阅器
然后再回到MainActivity
将这四个报错的返回方法注释掉,这是你的页面是不会有报错的,然后再运行一下,确保没有问题。好了,已经运行过没有问题了,那么最后就是删除掉注释的代码了。
这四个实体bean也可以删除了,删除之后再运行一下,OK,没有问题。也算是为应用做了一次瘦身了,下面就是优化一下用户的体验。
优化UI
增加逐小时天气预报详情和七天天气预报详情,
这个我打算用弹窗来做,首先是逐小时天气预报的详情,创建一个弹窗的背景样式
在项目的drawable下创建shape_white_5.xml文件
样式代码如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp" />
<solid android:color="#FFF" />
</shape>
① 逐小时天气预报的详情UI
在项目的layout文件下创建window_hourly_detail.xml文件
布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@drawable/shape_white_5"
android:padding="@dimen/dp_12"
android:layout_width="300dp"
android:layout_height="400dp">
<TextView
android:gravity="center_vertical"
android:textColor="@color/black"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"/>
<!--温度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="温度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_tem"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--天气状况-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="天气状况"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_cond_txt"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风向360角度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风向360角度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_deg"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风向-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风向"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_dir"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风力-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风力"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_sc"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风速-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风速"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_spd"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--相对湿度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="相对湿度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_hum"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--大气压强-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="大气压强"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_pres"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--降水概率-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="降水概率"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_pop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--露点温度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="露点温度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_dew"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--云量-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="云量"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_cloud"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
由于这一次的弹窗是屏幕中间出现,所以增加动画效果和代码,在mvplibrary模块下的anim文件夹中增加出现和隐藏的动画xml文件
window_hidden_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="300"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.5"
android:toYScale="0.5" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
</set>
window_show_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="300"
android:fromXScale="0.6"
android:fromYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="1.0" />
</set>
然后在styles.xml文件中添加
这里还会用到一个测量的工具类SizeUtils.java
代码如下:
package com.llw.mvplibrary.utils;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
/**
* dp sp px 转换 view 测量工个类
*/
public final class SizeUtils {
private SizeUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Value of dp to value of px.
*
* @param dpValue The value of dp.
* @return value of px
*/
public static int dp2px(Context context, final float dpValue) {
final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* Value of px to value of dp.
*
* @param pxValue The value of px.
* @return value of dp
*/
public static int px2dp(Context context, final float pxValue) {
final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* Value of sp to value of px.
*
* @param spValue The value of sp.
* @return value of px
*/
public static int sp2px(Context context, final float spValue) {
final float fontScale = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* Value of px to value of sp.
*
* @param pxValue The value of px.
* @return value of sp
*/
public static int px2sp(Context context, final float pxValue) {
final float fontScale = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* Converts an unpacked complex data value holding a dimension to its final floating
* point value. The two parameters <var>unit</var> and <var>value</var>
* are as in {@link TypedValue#TYPE_DIMENSION}.
*
* @param value The value to apply the unit to.
* @param unit The unit to convert from.
* @return The complex floating point value multiplied by the appropriate
* metrics depending on its unit.
*/
public static float applyDimension(Context context, final float value, final int unit) {
DisplayMetrics metrics = context.getApplicationContext().getResources().getDisplayMetrics();
switch (unit) {
case TypedValue.COMPLEX_UNIT_PX:
return value;
case TypedValue.COMPLEX_UNIT_DIP:
return value * metrics.density;
case TypedValue.COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case TypedValue.COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f / 72);
case TypedValue.COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case TypedValue.COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f / 25.4f);
}
return 0;
}
/**
* Force get the size of view.
* <p>e.g.</p>
* <pre>
* SizeUtils.forceGetViewSize(view, new SizeUtils.onGetSizeListener() {
* Override
* public void onGetSize(final View view) {
* view.getWidth();
* }
* });
* </pre>
*
* @param view The view.
* @param listener The get size listener.
*/
public static void forceGetViewSize(final View view, final onGetSizeListener listener) {
view.post(new Runnable() {
@Override
public void run() {
if (listener != null) {
listener.onGetSize(view);
}
}
});
}
/**
* Return the width of view.
*
* @param view The view.
* @return the width of view
*/
public static int getMeasuredWidth(final View view) {
return measureView(view)[0];
}
/**
* Return the height of view.
*
* @param view The view.
* @return the height of view
*/
public static int getMeasuredHeight(final View view) {
return measureView(view)[1];
}
/**
* Measure the view.
*
* @param view The view.
* @return arr[0]: view's width, arr[1]: view's height
*/
public static int[] measureView(final View view) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp == null) {
lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
}
int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
int lpHeight = lp.height;
int heightSpec;
if (lpHeight > 0) {
heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY);
} else {
heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}
view.measure(widthSpec, heightSpec);
return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()};
}
///
// interface
///
public interface onGetSizeListener {
void onGetSize(View view);
}
}
现在去LiWindow.java中增加中间显示的代码.
增加的代码我也贴一下:
/**
* 中间显示
* @param mView
*/
public void showCenterPopupWindow(View mView,int width,int height) {
mPopupWindow = new PopupWindow(mView,
width, height, true);
mPopupWindow.setContentView(mView);
mPopupWindow.setAnimationStyle(R.style.AnimationCenterFade); //设置动画
mPopupWindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
mPopupWindow.update();
setBackgroundAlpha(0.5f,mContext);
WindowManager.LayoutParams nomal = ((Activity) mContext).getWindow().getAttributes();
nomal.alpha = 0.5f;
((Activity) mContext).getWindow().setAttributes(nomal);
mPopupWindow.setOnDismissListener(closeDismiss);
}
现在修改item_weather_hourly_list.xml,增加了一个id和点击的水波纹效果,代码如下,复制粘贴即可:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_horizontal"
android:id="@+id/item_hourly"
android:foreground="@drawable/bg_white"
android:padding="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--时间-->
<TextView
android:id="@+id/tv_time"
android:textColor="#FFF"
android:text="上午10:00"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!--气候图标-->
<ImageView
android:layout_marginTop="12dp"
android:layout_marginBottom="8dp"
android:id="@+id/iv_weather_state"
android:background="@mipmap/icon_100"
android:layout_width="30dp"
android:layout_height="30dp"/>
<!--温度-->
<TextView
android:textSize="20sp"
android:id="@+id/tv_temperature"
android:textColor="#FFF"
android:text="25℃"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
再修改WeatherHourlyAdapter.java适配器
添加点击事件的id。
进入MainActivity.java
这个代码就手写一下吧,也不多,然后是这个弹窗的方法
//显示逐三小时详情天气信息弹窗
private void showHourlyWindow(WeatherResponse.HeWeather6Bean.HourlyBean data) {
liWindow = new LiWindow(context);
final View view = LayoutInflater.from(context).inflate(R.layout.window_hourly_detail, null);
TextView tv_time = view.findViewById(R.id.tv_time);//时间
TextView tv_tem = view.findViewById(R.id.tv_tem);//温度
TextView tv_cond_txt = view.findViewById(R.id.tv_cond_txt);//天气状态描述
TextView tv_wind_deg = view.findViewById(R.id.tv_wind_deg);//风向360角度
TextView tv_wind_dir = view.findViewById(R.id.tv_wind_dir);//风向
TextView tv_wind_sc = view.findViewById(R.id.tv_wind_sc);//风力
TextView tv_wind_spd = view.findViewById(R.id.tv_wind_spd);//风速
TextView tv_hum = view.findViewById(R.id.tv_hum);//相对湿度
TextView tv_pres = view.findViewById(R.id.tv_pres);//大气压强
TextView tv_pop = view.findViewById(R.id.tv_pop);//降水概率
TextView tv_dew = view.findViewById(R.id.tv_dew);//露点温度
TextView tv_cloud = view.findViewById(R.id.tv_cloud);//云量
String datetime = data.getTime();//赋值
String time = datetime.substring(11);//截去前面的字符,保留后面所有的字符,就剩下 22:00
tv_time.setText(WeatherUtil.showTimeInfo(time) + time);
tv_tem.setText(data.getTmp() + "℃");
tv_cond_txt.setText(data.getCond_txt());
tv_wind_deg.setText(data.getWind_deg()+"°");
tv_wind_dir.setText(data.getWind_dir());
tv_wind_sc.setText(data.getWind_sc()+"级");
tv_wind_spd.setText(data.getWind_spd() + "公里/小时");
tv_hum.setText(data.getHum());
tv_pres.setText(data.getPres());
tv_pop.setText(data.getPop() + "%");
tv_dew.setText(data.getDew()+"℃");
tv_cloud.setText(data.getCloud());
liWindow.showCenterPopupWindow(view, SizeUtils.dp2px(context, 300),SizeUtils.dp2px(context, 400));
}
OK,到目前为止,可以运行一下了
OK,还是蛮简单的吧(PS:由于没有UI,大家这个都知道开发的审美,就先将就一下,如果有好的建议可以给我提)。
② 未来七天天气的详情UI
其实这个和逐小时的比较类似,不过要比逐小时的数据要多一些,
在项目的layout文件下创建window_forecast_detail.xml文件
布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@drawable/shape_white_5"
android:padding="@dimen/dp_12"
android:layout_width="300dp"
android:layout_height="500dp">
<TextView
android:gravity="center_vertical"
android:textColor="@color/black"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
android:id="@+id/tv_datetime"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"/>
<!--最高温-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="最高温"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_tmp_max"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--最低温-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="最低温"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_tmp_min"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--紫外线强度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="紫外线强度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_uv_index"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--白天天气状况-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="白天天气状况"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_cond_txt_d"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--晚上天气状况-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="晚上天气状况"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_cond_txt_n"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风向360角度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风向360角度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_deg"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风向-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风向"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_dir"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风力-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风力"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_sc"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--风速-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="风速"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_wind_spd"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--相对湿度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="相对湿度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_hum"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--大气压强-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="大气压强"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_pres"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--降水量-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="降水量"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_pcpn"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--降水概率-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="降水概率"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_pop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
<!--能见度-->
<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:text="能见度"
android:textColor="@color/black"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<TextView
android:textColor="@color/black"
android:id="@+id/tv_vis"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
修改item_weather_forecast_list.xml增加ID和点击效果
修改WeatherForecastAdapter.java,绑定点击事件的id
这里先添加一个事件日期的工具类进去,是我好久之前写的,不过也能用的上DateUtils.java,代码如下:
package com.llw.goodweather.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class DateUtils {
//获取当前完整的日期和时间
public static String getNowDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
//获取当前日期
public static String getNowDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
//前一天
public static String getYesterday(Date date) {
String tomorrow = "";
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(calendar.DATE, -1);
date = calendar.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
tomorrow = formatter.format(date);
return tomorrow;
}
//后一天
public static String getTomorrow(Date date) {
String tomorrow = "";
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.add(calendar.DATE, +1);
date = calendar.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
tomorrow = formatter.format(date);
return tomorrow;
}
//获取当前时间
public static String getNowTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
//获取当前日期(精确到毫秒)
public static String getNowTimeDetail() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
return sdf.format(new Date());
}
//获取今天是星期几
public static String getWeekOfDate(Date date) {
String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
return weekDays[w];
}
//计算星期几
private static int getDayOfWeek(String dateTime) {
Calendar cal = Calendar.getInstance();
if (dateTime.equals("")) {
cal.setTime(new Date(System.currentTimeMillis()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
Date date;
try {
date = sdf.parse(dateTime);
} catch (ParseException e) {
date = null;
e.printStackTrace();
}
if (date != null) {
cal.setTime(new Date(date.getTime()));
}
}
return cal.get(Calendar.DAY_OF_WEEK);
}
//根据年月日计算是星期几并与当前日期判断 非昨天、今天、明天 则以星期显示
public static String Week(String dateTime) {
String week = "";
String yesterday = "";
String today = "";
String tomorrow = "";
yesterday = getYesterday(new Date());
today = getNowDate();
tomorrow = getTomorrow(new Date());
if (dateTime.equals(yesterday)) {
week = "昨天";
} else if (dateTime.equals(today)) {
week = "今天";
} else if (dateTime.equals(tomorrow)) {
week = "明天";
} else {
switch (getDayOfWeek(dateTime)) {
case 1:
week = "星期日";
break;
case 2:
week = "星期一";
break;
case 3:
week = "星期二";
break;
case 4:
week = "星期三";
break;
case 5:
week = "星期四";
break;
case 6:
week = "星期五";
break;
case 7:
week = "星期六";
break;
}
}
return week;
}
//将时间戳转化为对应的时间(10位或者13位都可以)
public static String formatTime(long time) {
String times = null;
if (String.valueOf(time).length() > 10) {// 10位的秒级别的时间戳
times = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time * 1000));
} else {// 13位的秒级别的时间戳
times = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time);
}
return times;
}
//将时间字符串转为时间戳字符串
public static String getStringTimestamp(String time) {
String timestamp = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Long longTime = sdf.parse(time).getTime() / 1000;
timestamp = Long.toString(longTime);
} catch (ParseException e) {
e.printStackTrace();
}
return timestamp;
}
}
修改MainActivity.java
这里添加的代码,你就手写一下吧,至于里面的showForecastWindow,代码如下:
//显示天气预报详情弹窗
private void showForecastWindow(WeatherResponse.HeWeather6Bean.DailyForecastBean data) {
liWindow = new LiWindow(context);
final View view = LayoutInflater.from(context).inflate(R.layout.window_forecast_detail, null);
TextView tv_datetime = view.findViewById(R.id.tv_datetime);
TextView tv_tmp_max = view.findViewById(R.id.tv_tmp_max);//最高温
TextView tv_tmp_min = view.findViewById(R.id.tv_tmp_min);//最低温
TextView tv_uv_index = view.findViewById(R.id.tv_uv_index);//紫外线强度
TextView tv_cond_txt_d = view.findViewById(R.id.tv_cond_txt_d);//白天天气状态
TextView tv_cond_txt_n = view.findViewById(R.id.tv_cond_txt_n);//晚上天气状态
TextView tv_wind_deg = view.findViewById(R.id.tv_wind_deg);//风向360角度
TextView tv_wind_dir = view.findViewById(R.id.tv_wind_dir);//风向
TextView tv_wind_sc = view.findViewById(R.id.tv_wind_sc);//风力
TextView tv_wind_spd = view.findViewById(R.id.tv_wind_spd);//风速
TextView tv_hum = view.findViewById(R.id.tv_hum);//相对湿度
TextView tv_pres = view.findViewById(R.id.tv_pres);//大气压强
TextView tv_pcpn = view.findViewById(R.id.tv_pcpn);//降水量
TextView tv_pop = view.findViewById(R.id.tv_pop);//降水概率
TextView tv_vis = view.findViewById(R.id.tv_vis);//能见度
tv_datetime.setText(data.getDate() +" "+ DateUtils.Week(data.getDate()));//时间日期
tv_tmp_max.setText(data.getTmp_max() + "℃");
tv_tmp_min.setText(data.getTmp_min() + "℃");
tv_uv_index.setText(data.getUv_index());
tv_cond_txt_d.setText(data.getCond_txt_d());
tv_cond_txt_n.setText(data.getCond_txt_n());
tv_wind_deg.setText(data.getWind_deg() + "°");
tv_wind_dir.setText(data.getWind_dir());
tv_wind_sc.setText(data.getWind_sc() + "级");
tv_wind_spd.setText(data.getWind_spd() + "公里/小时");
tv_hum.setText(data.getHum());
tv_pres.setText(data.getPres());
tv_pcpn.setText(data.getPcpn());
tv_pop.setText(data.getPop() + "%");
tv_vis.setText(data.getVis());
liWindow.showCenterPopupWindow(view, SizeUtils.dp2px(context, 300), SizeUtils.dp2px(context, 500));
}
运行效果如下:
到了这里,天气APP的第十四篇文章就写完了,感触良多啊,
源码地址:GoodWeather
欢迎 Star 和 Fork