1.项目功能思维导图
2. 项目涉及到的技术点
- 数据来源:和风天气API
- 使用okhttp网络请求框架获取api数据
- 使用gson库解析json数据
- 使用RecyclerView+adapter实现未来7天列表展示和天气指数
- 使用PopupMenu 实现弹出选项框
- 使用动画+定时器实现欢迎页倒计时和logo动画
- 使用TextToSpeech 实现语音播报
3.项目截图
4.部分代码功能实现
- 欢迎页实现
public class WelcomeActivity extends AppCompatActivity {
private TextView tvCountdown;
private CardView card_logo;
private CountDownTimer countDownTimer;
private long timeLeftInMillis = 1000; // 设置倒计时时长,单位为毫秒
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
//初始化控件
tvCountdown = findViewById(R.id.tv_countdown);
card_logo = findViewById(R.id.card_logo);
// 启动倒计时
startCountdown();
//实现logo缩放动画
startAnim();
}
private void startAnim() {
ViewCompat.animate(card_logo)
.scaleX(1.0f)
.scaleY(1.0f)
.setDuration(1000)
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
}
@Override
public void onAnimationEnd(View view) {
}
@Override
public void onAnimationCancel(View view) {
}
})
.start();
}
private void startCountdown() {
countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) {
@Override
public void onTick(long millisUntilFinished) {
timeLeftInMillis = millisUntilFinished;
int secondsRemaining = (int) (millisUntilFinished / 1000);
tvCountdown.setText(secondsRemaining + "s | 跳转");
}
@Override
public void onFinish() {
//跳转到登录页面(看自己逻辑想跳转哪个页面)
startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
// 倒计时结束后的操作,例如跳转到主页面
finish();
}
}.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
}
- 天气指数
public class IndicesActivity extends AppCompatActivity {
private String city_id;
private RecyclerView recyclerView;
private IndicesListAdapter mIndicesListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_indices);
//获取跳转传值
city_id = getIntent().getStringExtra("city_id");
//获取生活指数
getWeatherIndices(city_id);
//初始化控件
initViews();
//初始化适配器
mIndicesListAdapter = new IndicesListAdapter();
//设置适配器
recyclerView.setAdapter(mIndicesListAdapter);
//设置监听器
setListener();
}
/**
* 初始化控件
*/
private void initViews() {
recyclerView = findViewById(R.id.recyclerView);
}
/**
* 设置监听器
*/
private void setListener() {
findViewById(R.id.toolbar).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
/**
* 获取生活指数
*/
private void getWeatherIndices(String city_id) {
OkGo.<String>get("https://devapi.qweather.com/v7/indices/1d")
.params("location", city_id)
.params("key", ApiConstants.APP_KEY)
.params("type", "0")
.execute(new StringCallback() {
@Override
public void onStart(Request<String, ? extends Request> request) {
super.onStart(request);
ProgressDialogUtils.showProgressDialog(IndicesActivity.this);
}
@Override
public void onSuccess(Response<String> response) {
IndicesInfo indicesInfo = new Gson().fromJson(response.body(), IndicesInfo.class);
if (null != indicesInfo && indicesInfo.getCode().equals("200")) {
mIndicesListAdapter.setIndicesInfoList(indicesInfo.getDaily());
}
}
@Override
public void onFinish() {
super.onFinish();
ProgressDialogUtils.hideProgressDialog();
}
});
}
}
- 城市搜索
public class SearchActivity extends AppCompatActivity {
private EditText et_search_city;
private RecyclerView recyclerView;
private LinearLayoutCompat ll_empty;
private SearchListAdapter mSearchListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
// 1. 初始化控件
initViews();
//创建适配器
mSearchListAdapter = new SearchListAdapter();
//设置适配器
recyclerView.setAdapter(mSearchListAdapter);
// 2. 点击事件
setListener();
}
/**
* 初始化控件
*/
private void initViews() {
et_search_city = findViewById(R.id.et_search_city);
recyclerView = findViewById(R.id.recyclerView);
ll_empty = findViewById(R.id.ll_empty);
}
/**
* 点击事件
*/
private void setListener() {
findViewById(R.id.btn_search).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 1. 获取输入框的值
String cityName = et_search_city.getText().toString().trim();
// 2. 判断是否为空
if (cityName.isEmpty()) {
// 提示用户
Toast.makeText(SearchActivity.this, "城市名不能为空", Toast.LENGTH_SHORT).show();
} else {
searchCity(cityName);
}
}
});
//返回
findViewById(R.id.toolbar).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
//recyclerView点击事件
mSearchListAdapter.setOnItemClickListener(new SearchListAdapter.OnItemClickListener() {
@Override
public void onItemClick(CityLocationInfo.LocationDTO locationDTO) {
// 1. 获取城市名
String cityName = locationDTO.getName();
Intent intent = new Intent();
intent.putExtra("cityName", cityName);
intent.putExtra("id", locationDTO.getId());
//设置跳转回传的值
setResult(1000, intent);
// 3. 关闭当前界面
finish();
}
});
}
/**
* 城市搜索
*/
private void searchCity(String cityName) {
OkGo.<String>get("https://geoapi.qweather.com/v2/city/lookup").params("location", cityName).params("key", ApiConstants.APP_KEY).execute(new StringCallback() {
@Override
public void onStart(Request<String, ? extends Request> request) {
super.onStart(request);
ProgressDialogUtils.showProgressDialog(SearchActivity.this);
}
@Override
public void onSuccess(Response<String> response) {
CityLocationInfo cityLocationInfo = new Gson().fromJson(response.body(), CityLocationInfo.class);
if (null != cityLocationInfo && cityLocationInfo.getCode().equals("200")) {
if (null != mSearchListAdapter) {
mSearchListAdapter.setCityLocationInfoList(cityLocationInfo.getLocation());
}
//判断是否显示空布局
if (mSearchListAdapter.getItemCount() > 0) {
ll_empty.setVisibility(View.GONE);
} else {
ll_empty.setVisibility(View.VISIBLE);
}
} else {
Toast.makeText(SearchActivity.this, "未查询到该城市", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(Response<String> response) {
super.onError(response);
}
@Override
public void onFinish() {
super.onFinish();
ProgressDialogUtils.hideProgressDialog();
}
});
}
}