网络资源模板--基于Android Studio 实现的天气预报App

发布于:2025-09-03 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

一、测试环境说明

二、项目简介

三、项目演示

四、部设计详情(部分)

首页

城市管理

五、项目源码 


一、测试环境说明

电脑环境

Windows 11

编写语言

JAVA

开发软件

Android Studio  (2020)

开发软件只要大于等于测试版本即可(近几年官网直接下载也可以),若是版本低于测试版本请自行测试。项目需要根据你的软件自行适配

二、项目简介

该项目采用和风天气API接口,并且实现了自动定位当前位置(百度定位SDK),语音播报功能(讯飞语音合成技术),天气通知功能等,自动定位、语音播报需要使用真机进行测试,模拟器无法实现对应功能。

该项目使用Android Studio软件 JAVA语言,Room数据库开发完成的一款天气预报App。

实时展示温度湿度等气象数据、提供24小时精准预报和未来15天趋势预测。空气质量、风向、生活建议,并且可以展示每小时每天的具体天气情况。

三、项目演示

网络资源模板--基于Android studio 天气预报App

四、部设计详情(部分)

首页

1.页面的结构

页面采用经典的ConstraintLayout约束布局,整体分为顶部工具栏、下拉刷新容器、嵌套滚动视图三大部分。

滚动视图内包含天气信息展示区、小时预报横向列表、多日预报纵向列表、空气质量环形进度面板、风向风力可视化风车组件以及生活建议列表等多个功能模块,通过合理的层级结构和约束关系实现复杂界面布局。

2.使用到的技术

技术运用方面融合了MVVM架构、LiveData数据观察、权限动态请求、百度定位SDK、RecyclerView多类型列表、下拉刷新控件和自定义视图组件。

同时集成讯飞语音合成技术实现天气播报功能,实现后台定时任务调度,形成完整的技术栈体系。

3.页面详细介绍

页面核心功能包括自动定位获取当地天气、支持城市切换搜索、实时展示温度湿度等气象数据、提供24小时精准预报和未来15天趋势预测。

创新性地采用环形进度条可视化空气质量指数,配合动态风车展示风力风向,生活指数模块提供穿衣、运动等多项实用建议,形成全方位的天气服务平台。

<?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:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg2"
    android:fitsSystemWindows="true"
    tools:context=".ui.MainActivity">
    <!--顶部标题-->
    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/materialToolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:ellipsize="middle"
            android:singleLine="true"
            android:text="城市天气"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_16" />
    </com.google.android.material.appbar.MaterialToolbar>

    <!--    可以优化成这样就不用带textview了,但是要在activity改
    <           com.google.android.material.appbar.MaterialToolbar-->
    <!--        android:id="@+id/materialToolbar"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="wrap_content"-->
    <!--        android:fitsSystemWindows="true"-->
    <!--        app:title="城市天气"-->
    <!--        app:titleTextColor="@color/white"-->
    <!--        app:titleCentered="true"-->
    <!--        app:layout_constraintEnd_toEndOf="parent"-->
    <!--        app:layout_constraintStart_toStartOf="parent"-->
    <!--        app:layout_constraintTop_toTopOf="parent"/>-->


    <!--下拉刷新视图-->
    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/lay_refresh"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_0"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/materialToolbar">
        <!--滚动视图-->
        <androidx.core.widget.NestedScrollView
            android:id="@+id/lay_scroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <!--页面主要内容视图-->
            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="@dimen/dp_0">
                <!--滑动距离布局-->
                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/lay_scroll_height"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent">
                    <!--天气状况-->
                    <TextView
                        android:id="@+id/tv_week"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="@dimen/dp_16"
                        android:layout_marginTop="@dimen/dp_8"
                        android:text="星期几"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_18"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />
                    <!--播放图标-->
                    <ImageView
                        android:id="@+id/iv_voice_broadcast"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginLeft="8dp"
                        android:background="@mipmap/icon_broadcast"
                        android:visibility="visible"
                        app:layout_constraintBottom_toBottomOf="@+id/tv_week"
                        app:layout_constraintLeft_toRightOf="@+id/tv_week"
                        app:layout_constraintTop_toTopOf="@+id/tv_week" />
                    <!--播报状态-->
                    <TextView
                        android:id="@+id/tv_broadcast_state"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="@dimen/dp_12"
                        android:textColor="@color/white"

                        app:layout_constraintBottom_toBottomOf="@+id/iv_voice_broadcast"
                        app:layout_constraintLeft_toRightOf="@+id/iv_voice_broadcast"
                        app:layout_constraintTop_toTopOf="@+id/iv_voice_broadcast" />
                    <!--温度-->
                    <TextView
                        android:id="@+id/tv_temp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/dp_24"
                        android:text="0"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_60"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@+id/tv_week" />
                    <!--摄氏度符号-->
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="℃"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_24"
                        app:layout_constraintStart_toEndOf="@+id/tv_temp"
                        app:layout_constraintTop_toTopOf="@+id/tv_temp" />
                    <!--当天最高温和最低温-->
                    <LinearLayout
                        android:id="@+id/lay_temp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="16dp"
                        app:layout_constraintEnd_toEndOf="@+id/tv_temp"
                        app:layout_constraintStart_toStartOf="@+id/tv_temp"
                        app:layout_constraintTop_toBottomOf="@+id/tv_temp">
                        <!--最高温-->
                        <TextView
                            android:id="@+id/tv_height"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:textColor="@color/white"
                            android:textSize="@dimen/sp_14" />
                        <!--最低温-->
                        <TextView
                            android:id="@+id/tv_low"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:textColor="@color/temp_min_tx"
                            android:textSize="@dimen/sp_14" />
                    </LinearLayout>
                    <!--天气状况和空气质量-->
                    <LinearLayout
                        android:id="@+id/lay_info_air_info"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:orientation="horizontal"
                        app:layout_constraintEnd_toEndOf="@+id/lay_temp"
                        app:layout_constraintStart_toStartOf="@+id/lay_temp"
                        app:layout_constraintTop_toBottomOf="@+id/lay_temp">
                        <!--天气状况-->
                        <TextView
                            android:id="@+id/tv_weather_info"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:textColor="@color/white"
                            android:textSize="@dimen/sp_14" />
                        <!--空气质量-->
                        <TextView
                            android:id="@+id/tv_air_info"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:paddingLeft="@dimen/dp_8"
                            android:textColor="@color/white"
                            android:textSize="@dimen/sp_14" />
                    </LinearLayout>
                    <!--城市-->
                    <TextView
                        android:id="@+id/tv_city"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="16dp"
                        android:text="城市"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_20"
                        app:layout_constraintEnd_toEndOf="@+id/tv_temp"
                        app:layout_constraintStart_toStartOf="@+id/tv_temp"
                        app:layout_constraintTop_toBottomOf="@+id/lay_info_air_info" />
                </androidx.constraintlayout.widget.ConstraintLayout>
                <!--App名称-->
                <TextView
                    android:id="@+id/tv_app_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/dp_16"
                    android:layout_marginTop="@dimen/dp_16"
                    android:drawableStart="@mipmap/icon_weather_sun"
                    android:drawablePadding="@dimen/dp_4"
                    android:text="祝你有个好心情"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_12"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/lay_scroll_height" />

                <!--上一次更新时间-->
                <TextView
                    android:id="@+id/tv_update_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="@dimen/dp_16"
                    android:text="最近更新时间:"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_12"
                    app:layout_constraintBottom_toBottomOf="@+id/tv_app_name"
                    app:layout_constraintEnd_toEndOf="@+id/lay_scroll_height"
                    app:layout_constraintTop_toTopOf="@+id/tv_app_name" />
                <!--分隔线 增加UI效果-->
                <View
                    android:id="@+id/view"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/dp_1"
                    android:layout_marginStart="@dimen/dp_16"
                    android:layout_marginTop="@dimen/dp_8"
                    android:layout_marginEnd="@dimen/dp_16"
                    android:alpha="0.1"
                    android:background="@color/white"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/tv_app_name" />
                <!--逐小时天气预报列表-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_hourly"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/dp_16"
                    android:paddingStart="@dimen/dp_16"
                    android:paddingEnd="@dimen/dp_16"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/view" />
                <!--天气预报列表-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_daily"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/rv_hourly" />
                <!--空气质量-->
                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/lay_air"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_constraintTop_toBottomOf="@+id/rv_daily"
                    tools:layout_editor_absoluteX="16dp">
                    <!--空气质量-->
                    <TextView
                        android:id="@+id/textView3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:layout_marginTop="8dp"
                        android:text="空气质量"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_18"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />
                    <!--污染指数-->
                    <TextView
                        android:id="@+id/textView4"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="16dp"
                        android:text="污染指数"
                        android:textColor="#DAEBEE"
                        android:textSize="14sp"
                        app:layout_constraintEnd_toStartOf="@+id/guideline3"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@+id/textView3" />

                    <com.work.goodweather.ui.view.RoundProgressBar
                        android:id="@+id/rpb_aqi"
                        android:layout_width="120dp"
                        android:layout_height="120dp"
                        android:layout_gravity="center"
                        android:layout_marginTop="8dp"
                        app:layout_constraintEnd_toStartOf="@+id/guideline3"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@+id/textView4"
                        app:round_bg_color="#C6D7F4"
                        app:round_progress_color="#FBFEF7" />

                    <androidx.constraintlayout.widget.Guideline
                        android:id="@+id/guideline3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        app:layout_constraintGuide_begin="205dp" />

                    <TextView
                        android:id="@+id/textView5"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="PM10"
                        android:textColor="@color/ari_tx_color"
                        android:textSize="12sp"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView4"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toTopOf="@+id/textView4" />

                    <TextView
                        android:id="@+id/tv_pm10"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/textView5"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />

                    <TextView
                        android:id="@+id/textView6"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="PM2.5"
                        android:textColor="@color/ari_tx_color"
                        android:textSize="12sp"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toBottomOf="@+id/textView5" />

                    <TextView
                        android:id="@+id/tv_pm25"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/textView6"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />
                    <!--NO2 二氧化氮-->
                    <LinearLayout
                        android:id="@+id/lay_air_no"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toBottomOf="@+id/textView6">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="NO"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="12sp" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="top"
                            android:text="2"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="8sp" />
                    </LinearLayout>

                    <TextView
                        android:id="@+id/tv_no2"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/lay_air_no"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />
                    <!--NO2 二氧化硫-->
                    <LinearLayout
                        android:id="@+id/lay_air_so"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toBottomOf="@+id/lay_air_no">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="SO"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="12sp" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="top"
                            android:text="2"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="8sp" />
                    </LinearLayout>

                    <TextView
                        android:id="@+id/tv_so2"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/lay_air_so"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />
                    <!--O3 臭氧-->
                    <LinearLayout
                        android:id="@+id/lay_air_o3"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toBottomOf="@+id/lay_air_so">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="O"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="12sp" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="top"
                            android:text="3"
                            android:textColor="@color/ari_tx_color"
                            android:textSize="8sp" />
                    </LinearLayout>

                    <TextView
                        android:id="@+id/tv_o3"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/lay_air_o3"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />

                    <TextView
                        android:id="@+id/textView7"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="CO"
                        android:textColor="@color/ari_tx_color"
                        android:textSize="12sp"
                        app:layout_constraintEnd_toStartOf="@+id/tv_pm10"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toStartOf="@+id/guideline3"
                        app:layout_constraintTop_toBottomOf="@+id/lay_air_o3" />

                    <TextView
                        android:id="@+id/tv_co"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:textColor="@color/white"
                        android:textSize="12sp"
                        app:layout_constraintBottom_toBottomOf="@+id/textView7"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_bias="0.5"
                        app:layout_constraintStart_toEndOf="@+id/textView5" />
                </androidx.constraintlayout.widget.ConstraintLayout>
                <!--风向风力-->
                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/dp_16"
                    android:layout_marginTop="16dp"
                    android:text="风向风力"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_18"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/lay_air" />
                <!--大风车-->
                <com.work.goodweather.ui.view.WhiteWindmills
                    android:id="@+id/ww_big"
                    android:layout_width="100dp"
                    android:layout_height="120dp"
                    android:layout_marginTop="8dp"
                    app:layout_constraintEnd_toStartOf="@+id/guideline2"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/textView2"
                    tools:ignore="MissingConstraints" />
                <!--小风车-->
                <com.work.goodweather.ui.view.WhiteWindmills
                    android:id="@+id/ww_small"
                    android:layout_width="50dp"
                    android:layout_height="60dp"
                    android:layout_marginStart="32dp"
                    app:layout_constraintBottom_toBottomOf="@+id/ww_big"
                    app:layout_constraintEnd_toStartOf="@+id/guideline2"
                    app:layout_constraintStart_toStartOf="@+id/ww_big"
                    tools:ignore="MissingConstraints" />
                <!--纵向辅助线-->
                <androidx.constraintlayout.widget.Guideline
                    android:id="@+id/guideline2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    app:layout_constraintGuide_begin="205dp" />
                <!--风向风力文字-->
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    app:layout_constraintBottom_toBottomOf="@+id/ww_big"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="@+id/guideline2"
                    app:layout_constraintTop_toTopOf="@+id/ww_big">
                    <!--风向-->
                    <TextView
                        android:id="@+id/tv_wind_direction"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_14" />
                    <!--风力-->
                    <TextView
                        android:id="@+id/tv_wind_power"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/dp_24"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_14" />
                </LinearLayout>
                <!--生活建议-->
                <TextView
                    android:id="@+id/textView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/dp_16"
                    android:layout_marginTop="16dp"
                    android:text="生活建议"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_18"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/ww_big" />
                <!--生活建议列表-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_lifestyle"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:paddingStart="@dimen/dp_16"
                    android:paddingEnd="@dimen/dp_16"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/textView" />

            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.core.widget.NestedScrollView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

城市管理

1.页面的结构

页面采用简洁的线性布局结构,顶部为标题工具栏,中部为城市列表展示区域,底部为添加城市按钮。

城市列表项支持左右滑动操作,采用卡片式布局展示已保存的城市信息,整体界面清晰直观,符合材料设计规范。

2.使用到的技术

技术实现采用RecyclerView展示城市数据,配合ItemTouchHelper实现侧滑删除功能。

使用LiveData进行数据观察更新,通过AlertDialog实现删除确认交互。

采用MVVM架构进行数据管理,实现界面与数据的分离。

3.页面详细介绍

该页面主要提供城市管理功能,用户可查看已保存的城市列表,通过侧滑删除不需要的城市数据,点击底部按钮可弹出城市选择对话框添加新城市。

选择城市后会返回结果到天气主页面,实现城市数据的动态维护和快速切换。

package com.work.goodweather.ui;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;

import com.work.goodweather.Constant;
import com.work.goodweather.R;
import com.work.goodweather.databinding.ActivityManageCityBinding;
import com.work.goodweather.db.bean.MyCity;
import com.work.goodweather.ui.adapter.MyCityAdapter;
import com.work.goodweather.utils.AddCityDialog;
import com.work.goodweather.viewmodel.ManageCityViewModel;
import com.work.library.base.NetworkActivity;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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 -> setPageResult(myCityList.get(position).getCityName()));

        /**ManageCityActivity.this是ManageCityActivity的上下文(Context),它是创建LinearLayoutManager实例时必需的参数,
         因为布局管理器需要知道它所属的Activity或Fragment的上下文信息,以便正确地测量和布局子项。
         */
        binding.rvCity.setLayoutManager(new LinearLayoutManager(ManageCityActivity.this));
        binding.rvCity.setAdapter(myCityAdapter);
//        binding.btnAddCity.setOnClickListener(v -> showMsg("添加城市"));
        ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {

            @Override
            public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                //控制快速滑动的方向
                int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                return makeMovementFlags(0, swipeFlags);
            }

            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
                //显示提示弹窗
                showDeleteCity(viewHolder.getAdapterPosition());
            }

        });
        //关联recyclerView
        helper.attachToRecyclerView(binding.rvCity);

        binding.btnAddCity.setOnClickListener(v ->
                AddCityDialog.show(ManageCityActivity.this, Arrays.asList(Constant.CITY_ARRAY), cityName -> {
                    //保存到数据库中
                    viewModel.addMyCityData(cityName);
                    //设置页面返回数据
                    setPageResult(cityName);
                }));

    }
    private void showDeleteCity(int position) {
        // 声明对象
        AlertDialog dialog;
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle("删除城市")
                .setIcon(R.drawable.ic_round_delete_forever_24)
                .setMessage("您确定要删除吗?")
                .setPositiveButton("确定", (dialog1, which) -> {
                    MyCity myCity = myCityList.get(position);
                    myCityList.remove(position);
                    myCityAdapter.notifyItemRemoved(position);
                    viewModel.deleteMyCityData(myCity);
                    dialog1.dismiss();
                }).setNegativeButton("取消", (dialog12, which) -> {
                    myCityAdapter.notifyItemChanged(position);
                    dialog12.dismiss();
                });
        dialog = builder.create();
        dialog.show();
        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(Color.GRAY);
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.BLACK);
    }


    @Override
    protected void onObserveData() {
        /**
         * 在Android开发中,myCities -> {...} 是一个Lambda表达式的使用,它特别用于实现Observer接口的方法
         * (如LiveData的observe方法中的Observer回调)。从Android Jetpack的LiveData组件开始,这种简洁的语法被广泛用于响应数据变化。*/
        viewModel.listMutableLiveData.observe(this,myCities -> {
            if (myCities != null && myCities.size() > 0) {
                myCityList.clear();
                myCityList.addAll(myCities);
                myCityAdapter.notifyDataSetChanged();
            } else {
                showMsg("空空如也");
            }
        });
    }

    /**
     * 设置页面返回数据
     * @param cityName 城市名
     */
    private void setPageResult(String cityName) {
        Intent intent = new Intent();
        intent.putExtra(Constant.CITY_RESULT, cityName);
        setResult(Activity.RESULT_OK, intent);
        finish();
    }

}

五、项目源码 

👇👇👇👇👇快捷方式👇👇👇👇👇


网站公告

今日签到

点亮在社区的每一天
去签到