先看下app效果图:
App介绍:首次启动应用时列表显示全国34个省份及直辖市包括港澳台,如果选择省份进入所在省份下的市列表,如果再选择市项进入该市下所有的区或县(包括该市)列表,如果再选择该列表下的项就显示该区域的天气预报界面。图5从左滑出侧边栏可以选择其他城市。如果是非首次启动,则显示上次选择的城市天气预报界面(比如退出时显示广州的天气预报界面即图4,再次进入时仍显示该界面)。
具体app功能实现:
1.获取全国城市列表(图1到图3)
想罗列出中国所有的省份,只需要访问地址:http://guolin.tech/api/china,服务器会返回一段JSON格式的数据,包含中国所有省份名称以及省份id。如果想知道某个省份内有哪些城市,比如江苏的id是16,访问地址:http://guolin.tech/api/china/16。只需要把省份id添加到url地址的最后面即可。比如苏州的id是116,那么想知道苏州下有哪些县和区的时候,访问地址:http://guolin.tech/api/china/16/116。如此类推。
本app使用DataSupport这款开源的数据库框架进行城市查询,需要在app下的build.gradle导入:
implementation 'org.litepal.android:core:1.4.1'
在清单文件中的application节点中加入:
android:name="org.litepal.LitePalApplication"
此外还需要在assets目录下新建litepal.xml,构建名为weather_db的数据库,分别构建Province、City、County三张表。
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="weather_db"></dbname>
<version value="1"></version>
<list>
<mapping class="db.Province"/>
<mapping class="db.City"/>
<mapping class="db.County"/>
</list>
</litepal>
对于省份、城市、区或县进行数据库查询,则这些实体类需要继承自DataSupport:
package db;
import org.litepal.crud.DataSupport;
public class City extends DataSupport {
private int id;
private String cityName;
private int cityCode;
private int provinceId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public int getCityCode() {
return cityCode;
}
public void setCityCode(int cityCode) {
this.cityCode = cityCode;
}
public int getProvinceId() {
return provinceId;
}
public void setProvinceId(int provinceId) {
this.provinceId = provinceId;
}
}
package db;
import org.litepal.crud.DataSupport;
public class County extends DataSupport {
private int id;
private String countyName;
private String weatherId;
public String getWeatherId() {
return weatherId;
}
public void setWeatherId(String weatherId) {
this.weatherId = weatherId;
}
private int cityId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountyName() {
return countyName;
}
public void setCountyName(String countyName) {
this.countyName = countyName;
}
public int getCityId() {
return cityId;
}
public void setCityId(int cityId) {
this.cityId = cityId;
}
}
package db;
import org.litepal.crud.DataSupport;
public class Province extends DataSupport {
private int id;
private String provinceName;
private int provinceCode;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProvinceName() {
return provinceName;
}
public void setProvinceName(String provinceName) {
this.provinceName = provinceName;
}
public int getProvinceCode() {
return provinceCode;
}
public void setProvinceCode(int provinceCode) {
this.provinceCode = provinceCode;
}
}
访问服务器,所以需要在清单文件加入访问网络的权限:
<uses-permission android:name="android.permission.INTERNET" />
主程序布局仅由一个fragment组成,该fragment的布局由一个自定义的标题栏和一个listview组成:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/choose_are_fragment"
android:name="mini.org.miniweather.fragment.ChooseAreaFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
fragment的布局choose_area.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="match_parent"
android:orientation="vertical"
android:background="#fff"
android:fitsSystemWindows="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#fff"
android:layout_centerInParent="true"/>
<ImageView
android:id="@+id/back"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="10dp"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:background="@drawable/ic_back"/>
</RelativeLayout>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
城市列表显示界面ChooseAreaFragment,本文使用okhttp进行网络请求,所以需在build.gradle添加:
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
该fragment的代码及分析如下:
package mini.org.miniweather.fragment;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import org.litepal.crud.DataSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import db.City;
import db.County;
import db.Province;
import mini.org.miniweather.MainActivity;
import mini.org.miniweather.R;
import mini.org.miniweather.WeatherActivity;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import util.HttpUtil;
import util.Utility;
public class ChooseAreaFragment extends Fragment {
private static final int LEVEL_PROVINCE = 0;
private static final int LEVEL_CITY = 1;
private static final int LEVEL_COUNTY = 2;
private List<String> dataList = new ArrayList<>();
private ArrayAdapter<String> adapter;
private TextView titleText;
private ImageView backButton;
private ListView listView;
private ProgressDialog progressDialog;
/**
* 省列表
*/
private List<Province> provinceList;
/**
* 城市列表
*/
private List<City> cityList;
/**
* 城镇列表
*/
private List<County> countyList;
/**
* 当前等级
*/
private int currentLevel;
/**
* 选中的省份
*/
private Province selectedProvince;
/**
* 选中的城市
*/
private City selectedCity;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.choose_area,container,false);
titleText = (TextView)view.findViewById(R.id.title);
backButton = (ImageView)view.findViewById(R.id.back);
listView = (ListView)view.findViewById(R.id.listview);
adapter = new ArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
listView.setAdapter(adapter);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
queryProvinces();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (currentLevel == LEVEL_PROVINCE){
selectedProvince = provinceList.get(position);
queryCities();
}else if (currentLevel == LEVEL_CITY){
selectedCity = cityList.get(position);
queryCounties();
}else if (currentLevel == LEVEL_COUNTY){
String weatherId = countyList.get(position).getWeatherId();
if (getActivity() instanceof MainActivity){
Intent intent = new Intent(getActivity(), WeatherActivity.class);
intent.putExtra("weather_id",weatherId);
startActivity(intent);
getActivity().finish();
}else if (getActivity() instanceof WeatherActivity){
WeatherActivity activity = (WeatherActivity)getActivity();
activity.drawerLayout.closeDrawers();
activity.getWeatherInfo(weatherId);
}
}
}
});
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentLevel == LEVEL_COUNTY){
queryCities();
}else if (currentLevel == LEVEL_CITY){
queryProvinces();
}
}
});
}
/**
* 查询所有的省,优先从数据库查询,如果没有查到再去服务器上查询
*/
private void queryProvinces(){
titleText.setText("中国");
backButton.setVisibility(View.GONE);
provinceList = DataSupport.findAll(Province.class);
if (provinceList.size()>0){
dataList.clear();
for (Province province:provinceList){
dataList.add(province.getProvinceName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel = LEVEL_PROVINCE;
}else{
String address = "http://guolin.tech/api/china";
queryFromServer(address,"province");
}
}
/**
* 查询选中省内所有的市,优先从数据库查询,如果没有查询到再去服务器上查询。
*/
private void queryCities() {
titleText.setText(selectedProvince.getProvinceName());
backButton.setVisibility(View.VISIBLE);
cityList = DataSupport.where("provinceid = ?",
String.valueOf(selectedProvince.getId())).find(City.class);
if (cityList.size()>0){
dataList.clear();
for (City city:cityList){
dataList.add(city.getCityName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel = LEVEL_CITY;
}else {
int provinceCode = selectedProvince.getProvinceCode();
String address = "http://guolin.tech/api/china/"+provinceCode;
queryFromServer(address,"city");
}
}
/**
* 查询选中市内所有的县,优先从数据库查询,如果没有查询到再去服务器上查询。
*/
private void queryCounties() {
titleText.setText(selectedCity.getCityName());
backButton.setVisibility(View.VISIBLE);
countyList = DataSupport.where("cityid=?",
String.valueOf(selectedCity.getId())).find(County.class);
if (countyList.size() >0){
dataList.clear();
for (County county:countyList){
dataList.add(county.getCountyName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel = LEVEL_COUNTY;
}else{
int provinceCode = selectedProvince.getProvinceCode();
int cityCode = selectedCity.getCityCode();
String address = "http://guolin.tech/api/china/" + provinceCode + "/" + cityCode;
queryFromServer(address,"county");
}
}
/**
* 根据传入的地址和类型从服务器上查询省市县数据
* @param address
* @param type
*/
private void queryFromServer(String address, final String type) {
showProgressDialog();
HttpUtil.sendOkhttpRequest(address, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responceText = response.body().string();
boolean result = false;
if ("province".equals(type)){
result = Utility.handleProvinceResponce(responceText);
}else if ("city".equals(type)){
result = Utility.handleCityResponce(responceText,selectedProvince.getId());
}else if ("county".equals(type)){
result = Utility.handleCountyResponce(responceText,selectedCity.getId());
}
if(result){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvinces();
}else if ("city".equals(type)){
queryCities();
}else if ("county".equals(type)){
queryCounties();
}
}
});
}
}
});
}
/**
* 显示进度对话框
*/
private void showProgressDialog() {
if (progressDialog == null){
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("正在加载...");
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}
/**
* 关闭进度对话框
*/
private void closeProgressDialog(){
if (progressDialog!=null){
progressDialog.dismiss();
}
}
}
该fragment涉及的工具类如下:
package util;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HttpUtil {
public static void sendOkhttpRequest(String address,okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(address).build();
client.newCall(request).enqueue(callback);
}
}
package util;
import android.text.TextUtils;
import android.util.Log;
import com.google.gson.Gson;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import db.City;
import db.County;
import db.Province;
import interfaces.heweather.com.interfacesmodule.bean.weather.Weather;
public class Utility {
/**
* 解析和返回服务器返回的省级数据
*/
public static boolean handleProvinceResponce(String responce){
if (!TextUtils.isEmpty(responce)){
try {
JSONArray allProvinces = new JSONArray(responce);
for (int i=0;i<allProvinces.length();i++){
JSONObject provinceObject = allProvinces.getJSONObject(i);
Province province = new Province();
province.setProvinceName(provinceObject.getString("name"));
province.setProvinceCode(provinceObject.getInt("id"));
province.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 解析和返回服务器返回的市级数据
*/
public static boolean handleCityResponce(String responce,int provinceId){
if (!TextUtils.isEmpty(responce)){
try {
JSONArray allCities = new JSONArray(responce);
for (int i=0;i<allCities.length();i++){
JSONObject cityObject = allCities.getJSONObject(i);
City city = new City();
city.setCityName(cityObject.getString("name"));
city.setCityCode(cityObject.getInt("id"));
city.setProvinceId(provinceId);
city.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 解析和返回服务器返回的县级数据
*/
public static boolean handleCountyResponce(String responce,int cityId){
if (!TextUtils.isEmpty(responce)){
try {
JSONArray allCounties = new JSONArray(responce);
for (int i=0;i<allCounties.length();i++){
JSONObject countyObject = allCounties.getJSONObject(i);
County county = new County();
county.setCountyName(countyObject.getString("name"));
county.setWeatherId(countyObject.getString("weather_id"));
county.setCityId(cityId);
county.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
}
2.获取城市天气预报
本文使用和风天气平台提供的天气数据来源,关于如何使用该平台获得城市天气预报情况,可以参考Android 获取实时天气数据,在这就不多加赘述。
每次启动应用时,先去检查SharedPreference中保存键为"weather"的值(即和风天气需要获取天气情况的城市代码)是否为空,如为空,显示城市列表fragment即ChooseAreFragment,如不为空,则将该值通过Intent传递给城市天气预报界面WeatherActivity,并启动该Activity。
package mini.org.miniweather;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getString("weather",null)!= null){
Intent intent = new Intent(this,WeatherActivity.class);
startActivity(intent);
finish();
}
}
}
该WeatherActivity界面背景使用必应服务器提供的图片,使用Glide三方框架加载缓存的背景图片,代码及分析如下:
package mini.org.miniweather;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.List;
import interfaces.heweather.com.interfacesmodule.bean.Lang;
import interfaces.heweather.com.interfacesmodule.bean.Unit;
import interfaces.heweather.com.interfacesmodule.bean.air.now.AirNow;
import interfaces.heweather.com.interfacesmodule.bean.weather.Weather;
import interfaces.heweather.com.interfacesmodule.bean.weather.forecast.ForecastBase;
import interfaces.heweather.com.interfacesmodule.bean.weather.lifestyle.LifestyleBase;
import interfaces.heweather.com.interfacesmodule.view.HeConfig;
import interfaces.heweather.com.interfacesmodule.view.HeWeather;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import util.HttpUtil;
public class WeatherActivity extends AppCompatActivity {
private LinearLayout forecastLayout;
private TextView aqiText;
private TextView degreeText;
private TextView weatherInfoText;
private TextView pm25Text;
private String weatherId;
private TextView cityText;
private ImageView bingPicImg;
private TextView timeText;
private TextView weatherText;
private TextView comfortText;
private TextView carWashText;
private TextView sportText;
private Button navButton;
public DrawerLayout drawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >21){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
setContentView(R.layout.activity_weather);
initView();
initWeather();
}
private void initWeather() {
HeConfig.init("HE1912311406181054","045f6a9bffa44f06a72c4dc903082906");
HeConfig.switchToFreeServerNode();
}
private void initView() {
forecastLayout = (LinearLayout)findViewById(R.id.forecast_layout);
aqiText = (TextView)findViewById(R.id.aqi_text);
degreeText = (TextView)findViewById(R.id.degree_text);
weatherInfoText = (TextView)findViewById(R.id.weather_info_text);
pm25Text = (TextView)findViewById(R.id.pm25_text);
cityText = (TextView)findViewById(R.id.title_city);
bingPicImg = (ImageView)findViewById(R.id.bing_pic);
timeText = (TextView)findViewById(R.id.title_time);
comfortText = (TextView)findViewById(R.id.comfort_text);
carWashText = (TextView)findViewById(R.id.car_wash_text);
sportText = (TextView)findViewById(R.id.sport_text);
navButton = (Button)findViewById(R.id.nav_button);
drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String bingPic = prefs.getString("bing_pic", null);
if (bingPic != null) {
Glide.with(this).load(bingPic).into(bingPicImg);
} else {
loadBingPic();
}
weatherId = prefs.getString("weather",null);
if (weatherId == null){
weatherId = getIntent().getStringExtra("weather_id");
}
getWeatherInfo(weatherId);
navButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
}
/**
* 加载必应每日一图
*/
private void loadBingPic() {
String requestBingPic = "http://guolin.tech/api/bing_pic";
HttpUtil.sendOkhttpRequest(requestBingPic, new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
final String bingPic = response.body().string();
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("bing_pic", bingPic);
editor.apply();
runOnUiThread(new Runnable() {
@Override
public void run() {
Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);
}
});
}
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
});
}
/**
* 获取城市天气预报
* @param weatherid 城市代码
*/
public void getWeatherInfo(final String weatherid) {
weatherId = weatherid;
HeWeather.getWeather(WeatherActivity.this, weatherId,
Lang.CHINESE_SIMPLIFIED, Unit.METRIC, new HeWeather.OnResultWeatherDataListBeansListener() {
@Override
public void onError(Throwable throwable) {
}
@Override
public void onSuccess(Weather weather) {
Log.d("hdj", "status: " + weather.getStatus());
if (weather != null && "ok".equals(weather.getStatus())){
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("weather", weatherid);
editor.apply();
showWeatherInfo(weather);
}else{
Toast.makeText(WeatherActivity.this,"无法获得该区域的天气情况"
,Toast.LENGTH_LONG).show();
}
}
});
HeWeather.getAirNow(WeatherActivity.this, weatherId,
Lang.CHINESE_SIMPLIFIED, Unit.METRIC, new HeWeather.OnResultAirNowBeansListener() {
@Override
public void onError(Throwable throwable) {
}
@Override
public void onSuccess(AirNow airNow) {
showAirInfo(airNow);
}
});
}
/**
* 处理并展示Weather实体类中的数据。
*/
private void showWeatherInfo(Weather weather){
String cityName = weather.getBasic().getLocation();
String titleTime = weather.getUpdate().getLoc().split(" ")[1];
int hour = Integer.parseInt(titleTime.split(":")[0]);
boolean isDayTime = hour>=6&&hour<=18 ? true:false;
String weatherInfo = weather.getNow().getCond_txt();
String degreeInfo = weather.getNow().getTmp()+ "℃";
cityText.setText(cityName);
timeText.setText(titleTime);
weatherInfoText.setText(weatherInfo);
degreeText.setText(degreeInfo);
forecastLayout.removeAllViews();
for (ForecastBase forecast: weather.getDaily_forecast()) {
View view = LayoutInflater.from(this).inflate(R.layout.forecast_item, forecastLayout,
false);
TextView dateText = (TextView) view.findViewById(R.id.date_text);
TextView infoText = (TextView) view.findViewById(R.id.info_text);
TextView maxText = (TextView) view.findViewById(R.id.max_info);
TextView minText = (TextView) view.findViewById(R.id.min_info);
dateText.setText(forecast.getDate());
if (isDayTime) {
infoText.setText(forecast.getCond_txt_d());
}else{
infoText.setText(forecast.getCond_txt_n());
}
maxText.setText(forecast.getTmp_max()+"℃");
minText.setText(forecast.getTmp_min()+"℃");
forecastLayout.addView(view);
}
List<LifestyleBase> lifestyleBases = weather.getLifestyle();
comfortText.setText("舒适度:" +lifestyleBases.get(0).getTxt());
carWashText.setText("洗车指数:" + lifestyleBases.get(6).getTxt());
sportText.setText("出行建议:" + lifestyleBases.get(3).getTxt());
}
/**
* 显示空气质量
* @param airNow
*/
private void showAirInfo(AirNow airNow){
String airStatus = airNow.getStatus();
if (airStatus.equals("ok")){
String jsonData = new Gson().toJson(airNow.getAir_now_city());
JSONObject objectAir = null;
try {
objectAir = new JSONObject(jsonData);
String aqi = objectAir.getString("aqi");
String pm25 = objectAir.getString("pm25");
aqiText.setText(aqi);
pm25Text.setText(pm25);
} catch (JSONException e) {
e.printStackTrace();
}
}else {
aqiText.setText("无");
pm25Text.setText("无");
}
}
}
app的build.gradle中需要导入:
implementation 'com.github.bumptech.glide:glide:3.7.0'
以上就是整个app的具体介绍,具体思路大概是先通过DataSupport获取远程服务器上的城市列表,然后通过和风天气平台获取选中的城市天气预报及空气质量指数等。
最后附上WeatherActivity的相关布局文件代码:
activity_weather:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".WeatherActivity">
<ImageView
android:id="@+id/bing_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/weather_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:overScrollMode="never">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<include layout="@layout/title"/>
<include layout="@layout/now"/>
<include layout="@layout/forecast"/>
<include layout="@layout/aqi" />
<include layout="@layout/suggestion"/>
</LinearLayout>
</ScrollView>
<fragment
android:id="@+id/choose_are_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="mini.org.miniweather.fragment.ChooseAreaFragment"
/>
</android.support.v4.widget.DrawerLayout>
</FrameLayout>
title.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/nav_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_home"/>
<TextView
android:id="@+id/title_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="20sp"
android:textColor="#fff"/>
<TextView
android:id="@+id/title_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#fff"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"/>
</RelativeLayout>
now.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:orientation="vertical"
android:layout_margin="15dp">
<TextView
android:id="@+id/degree_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textColor="#fff"
android:textSize="60sp"/>
<TextView
android:id="@+id/weather_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textSize="20sp"
android:textColor="#fff"/>
</LinearLayout>
forecast.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="预报"
android:textColor="#fff"
android:textSize="20sp"/>
<LinearLayout
android:id="@+id/forecast_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
forecast_item.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="match_parent"
android:layout_margin="15dp">
<TextView
android:id="@+id/date_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:textColor="#fff"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/info_text"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="center"
android:textColor="#fff"/>
<TextView
android:id="@+id/max_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:textColor="#fff"
android:gravity="right"/>
<TextView
android:id="@+id/min_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:textColor="#fff"
android:gravity="right"/>
</LinearLayout>
aqi.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#fff"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text="空气质量"/>
<LinearLayout
android:layout_margin="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/aqi_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"
android:textSize="40sp"/>
<TextView
android:text="AQI指数"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/pm25_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"
android:textSize="40sp"/>
<TextView
android:text="PM2.5指数"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#fff"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
suggestion.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="#8000">
<TextView
android:text="生活建议"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginLeft="15dp"
android:textSize="20sp"
android:textColor="#fff"/>
<TextView
android:id="@+id/comfort_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:layout_margin="15dp"/>
<TextView
android:id="@+id/car_wash_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:layout_margin="15dp"/>
<TextView
android:id="@+id/sport_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:layout_margin="15dp"/>
</LinearLayout>
注:本文参考自欧酷天气开源项目。
来源:CSDN
作者:Xhaka_Jim
链接:https://blog.csdn.net/u010218230/article/details/104499548