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; // 设置倒计时时长,单位为毫秒@Overrideprotected 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() {@Overridepublic void onAnimationStart(View view) {}@Overridepublic void onAnimationEnd(View view) {}@Overridepublic void onAnimationCancel(View view) {}}).start();}private void startCountdown() {countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) {@Overridepublic void onTick(long millisUntilFinished) {timeLeftInMillis = millisUntilFinished;int secondsRemaining = (int) (millisUntilFinished / 1000);tvCountdown.setText(secondsRemaining + "s | 跳转");}@Overridepublic void onFinish() {//跳转到登录页面(看自己逻辑想跳转哪个页面)startActivity(new Intent(WelcomeActivity.this, MainActivity.class));// 倒计时结束后的操作,例如跳转到主页面finish();}}.start();}@Overrideprotected void onDestroy() {super.onDestroy();if (countDownTimer != null) {countDownTimer.cancel();}}
}
- 天气指数
public class IndicesActivity extends AppCompatActivity {private String city_id;private RecyclerView recyclerView;private IndicesListAdapter mIndicesListAdapter;@Overrideprotected 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() {@Overridepublic 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() {@Overridepublic void onStart(Request<String, ? extends Request> request) {super.onStart(request);ProgressDialogUtils.showProgressDialog(IndicesActivity.this);}@Overridepublic 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());}}@Overridepublic 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;@Overrideprotected 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() {@Overridepublic 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() {@Overridepublic void onClick(View view) {finish();}});//recyclerView点击事件mSearchListAdapter.setOnItemClickListener(new SearchListAdapter.OnItemClickListener() {@Overridepublic 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() {@Overridepublic void onStart(Request<String, ? extends Request> request) {super.onStart(request);ProgressDialogUtils.showProgressDialog(SearchActivity.this);}@Overridepublic 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();}}@Overridepublic void onError(Response<String> response) {super.onError(response);}@Overridepublic void onFinish() {super.onFinish();ProgressDialogUtils.hideProgressDialog();}});}
}