Android 天气APP(三十一)每日提醒弹窗

简介: Android 天气APP(三十一)每日提醒弹窗

效果图


20201204165427830.gif


每日提醒弹窗



前言


  为了增强用户的体验,所以增加了这个每日弹窗,每日弹窗顾名思义,每天弹出一次,就不再弹窗,当然如果用户觉得烦的话,可以在弹窗中勾选上不再弹窗,或者在应用设置中,关闭每日弹窗都是可以的。下面来写这个功能。


正文


说到弹窗我就想起来我之前的应用更新弹窗那一篇文章了,那么这个功能怎么来写呢?其实也不难,首先想清楚这个弹窗要什么东西。


① 是弹窗的背景,我希望每一天都不一样,那么就可以采用必应的每日一图。

② 弹窗可关闭不再弹出,可以通过缓存的方式判断处理,

③ 弹窗上面显示的值,可以通过主页面其它接口先获取到返回值,然后在弹窗中显示,

④ 每日只弹出一次,这个就是要在每日弹出弹窗时,存储一个时间戳缓存,后面再进入APP时判断时间大小就可以了。


这么一看,目标就明确了,下面进入实操环节。


一、弹窗背景


 还记得之前我在写壁纸页面的时候,把必应的请求放到壁纸管理页面了,那么主页面就没有请求了,而我又需要这个请求获取每日的壁纸url。所以在欢迎页面新增了一个请求。


打开SplashContract,新增如下代码:



    /**
         * 获取必应  每日一图
         */
        public void biying() {
            ApiService service = ServiceGenerator.createService(ApiService.class, 1);
            service.biying().enqueue(new NetCallBack<BiYingImgResponse>() {
                @Override
                public void onSuccess(Call<BiYingImgResponse> call, Response<BiYingImgResponse> response) {
                    if (getView() != null) {
                        getView().getBiYingResult(response);
                    }
                }
                @Override
                public void onFailed() {
                    if (getView() != null) {
                        getView().getDataFailed();
                    }
                }
            });
        }


    /**
         * 获取必应每日一图返回
         * @param response BiYingImgResponse
         */
        void getBiYingResult(Response<BiYingImgResponse> response);


增加位置如下:


20201204161654911.png


然后进入SplashActivity,重写getBiYingResult方法,代码如下:


  /**
     * 必应壁纸数据返回
     *
     * @param response BiYingImgResponse
     */
    @Override
    public void getBiYingResult(Response<BiYingImgResponse> response) {
        if (response.body().getImages() != null) {
            //得到的图片地址是没有前缀的,所以加上前缀否则显示不出来
            String biyingUrl = "http://cn.bing.com" + response.body().getImages().get(0).getUrl();
            SPUtils.putString(Constant.EVERYDAY_TIP_IMG,biyingUrl,context);
        } else {
            ToastUtils.showShortToast(context, "未获取到必应的图片");
        }
    }


这里你会发现Constant.EVERYDAY_TIP_IMG,没有这个属性值,那么就到Constant中去创建。


  /**
     * 每日提示弹窗的背景图
     */
    public static final String EVERYDAY_TIP_IMG = "everydayTipImg";
    /**
     * 每日提示弹窗是否弹出
     */
    public static final String EVERYDAY_POP_BOOLEAN = "everydayPopBoolean";


在Constant里面增加这两个系统变量,注释已经说明了这两个变量的用途了。

下面在layout中新建一个dialog_everyday_tip.xml。里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="@dimen/dp_270"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <!--弹窗背景图-->
    <com.google.android.material.imageview.ShapeableImageView
        android:id="@+id/iv_dialog_bg"
        android:layout_width="match_parent"
        android:layout_height="420dp"
        android:foreground="@drawable/shape_dialog_foreground_bg_12"
        android:scaleType="fitXY"
        android:src="@drawable/img_5"
        app:shapeAppearanceOverlay="@style/roundedImageStyle" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="420dp"
        android:padding="@dimen/dp_12">
        <TextView
            android:id="@+id/tv_week"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="星期四"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_20"
            android:textStyle="bold" />
        <!--温度-->
        <TextView
            android:id="@+id/tv_temperature"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_week"
            android:text="温度"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_48" />
        <!--天气状态-->
        <TextView
            android:id="@+id/tv_weather_state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_temperature"
            android:text="天气"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_20"
            android:typeface="monospace" />
        <!--天气状态图标-->
        <ImageView
            android:id="@+id/iv_weather_state"
            android:layout_width="@dimen/dp_80"
            android:layout_height="@dimen/dp_80"
            android:layout_alignParentRight="true"
            android:src="@mipmap/icon_100" />
        <!--降水预告-->
        <TextView
            android:id="@+id/tv_precipitation"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/iv_weather_state"
            android:layout_alignParentRight="true"
            android:layout_marginTop="@dimen/dp_10"
            android:drawableLeft="@mipmap/icon_weather_prec"
            android:drawablePadding="4dp"
            android:text="降水预告"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_12" />
        <!--温差提示-->
        <TextView
            android:id="@+id/tv_temp_difference"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_weather_state"
            android:layout_marginTop="@dimen/dp_100"
            android:text="温差提示"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_18"
            android:typeface="monospace" />
        <!--不再弹出-->
        <com.google.android.material.checkbox.MaterialCheckBox
            android:id="@+id/cb_no_pop_up"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:text="不再弹出"
            android:textSize="@dimen/sp_16"
            app:useMaterialThemeColors="true"
            app:buttonTint="@color/gray"
            android:textColor="@color/gray" />
    </RelativeLayout>
    <View
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/iv_dialog_bg"
        android:background="@color/white"
        android:layout_width="@dimen/dp_1"
        android:layout_height="@dimen/dp_12"/>
    <ImageView
        android:id="@+id/iv_close"
        android:layout_width="@dimen/dp_24"
        android:layout_height="@dimen/dp_24"
        android:layout_below="@+id/iv_dialog_bg"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/dp_12"
        android:src="@mipmap/icon_close_dialog" />
</RelativeLayout>


预览图如下所示(里面的图标没有的话可以去我的源码里面下载,或者自行下载一个,因为是白色的所示我贴了也看不见,CSDN中,不开会员的人无法修改文章的主题颜色,免费的主题,改不了博文的颜色,这一点我觉得很坑,非要你开个会员,吃相太难看了)


20201204162048677.png



这里面用到了一个style,在app的styles.xml中增加如下代码:

  <!-- 圆角图片 -->
    <style name="roundedImageStyle">
        <item name="cornerFamily">rounded</item>
        <item name="cornerSize">12dp</item>
    </style>


在drawable下新建一个shape_dialog_foreground_bg_12.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="@dimen/dp_12" />
    <solid android:color="@color/transparent_bg_1" />
</shape>


在app的colors.xml中新增一个颜色

<color name="transparent_bg_1">#20000000</color><!--黑色半透明 一-->


布局有了,那么就是先改变背景,再增加数据。


二、每天第一次弹窗


下面进入到MainActivity中,将检查版本更新的方法移动一个位置


20201204163216305.png


因为自动更新的弹窗也是在每日第一次才弹出,所以公用,不过也要修改一下checkAppVersion里面的逻辑才行。修改后代码如下:


  /**
     * 检查APP版本
     */
    private void checkAppVersion() {
        AppVersion appVersion = LitePal.find(AppVersion.class, 1);//读取第一条数据
        Log.d("appVersion", new Gson().toJson(appVersion.getVersionShort()));
        if (AppStartUpUtils.isTodayFirstStartApp(context)) {//今天第一次打开APP
            if (!appVersion.getVersionShort().equals(APKVersionInfoUtils.getVerName(context))) {//提示更新
                //更新提示弹窗
                showUpdateAppDialog(appVersion.getInstall_url(), appVersion.getChangelog());
            }
            //设置每日提示弹窗
            setTipDialog();
        }
    }


之前是判断可不可以更新,再判断是否为第一次,现在判断是否为第一次打开。

然后下面的重点就是这个setTipDialog方法了


  /**
     * 设置每日弹窗
     */
    private void setTipDialog() {
        boolean isShow = SPUtils.getBoolean(Constant.EVERYDAY_POP_BOOLEAN, true, context);
        if (isShow) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    //当所有数据加载完成之后显示弹窗
                    if (everyDayTipDialog != null) {
                        return;
                    }
                    //弹出每日提醒弹窗
                    showEveryDayTipDialog();
                }
            },1000);
        }
    }


这里用到那么那个系统变量,判断是否可以弹窗这个弹窗,然后延时弹出。


三、弹出每日提示弹窗


  /**
     * 每日提示弹窗
     */
    private void showEveryDayTipDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(context)
                .addDefaultAnimation()//默认弹窗动画
                .setCancelable(false)
                .setText(R.id.tv_week, DateUtils.getWeekOfDate(new Date()))//星期
                .setText(R.id.tv_weather_state, dialogWeatherState)//天气状态
                .setText(R.id.tv_precipitation, dialogPrecipitation)//降水预告
                .setText(R.id.tv_temp_difference,
                        WeatherUtil.differenceTempTip(dialogTempHeight, dialogTempLow))//温差提示信息
                .setContentView(R.layout.dialog_everyday_tip)//载入布局文件
                .setWidthAndHeight(SizeUtils.dp2px(context, 270), ViewGroup.LayoutParams.WRAP_CONTENT)//设置弹窗宽高
                .setOnClickListener(R.id.iv_close, v -> {//关闭
                    everyDayTipDialog.dismiss();
                });
        everyDayTipDialog = builder.create();
        String imgUrl = SPUtils.getString(Constant.EVERYDAY_TIP_IMG, "", context);
        ShapeableImageView bg = everyDayTipDialog.getView(R.id.iv_dialog_bg);
        Glide.with(context).load(imgUrl).into(bg);
        //温度
        Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Light.ttf");
        TextView temp = everyDayTipDialog.getView(R.id.tv_temperature);
        temp.setTypeface(typeface);
        temp.setText(dialogTemp + "℃");
        //设置天气状态图标
        ImageView weatherStateIcon = everyDayTipDialog.getView(R.id.iv_weather_state);
        WeatherUtil.changeIcon(weatherStateIcon, dialogWeatherStateCode);
        //不再弹出
        MaterialCheckBox cb = everyDayTipDialog.getView(R.id.cb_no_pop_up);
        cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    SPUtils.putBoolean(Constant.EVERYDAY_POP_BOOLEAN, false, context);
                } else {
                    SPUtils.putBoolean(Constant.EVERYDAY_POP_BOOLEAN, true, context);
                }
            }
        });
        everyDayTipDialog.show();
    }


这里面的代码就是先显示一些要的数据,通过缓存拿到必应的url设置背景,然后在弹窗的底部有一个选中框,选中后再关闭这个弹窗,那么这个弹窗以后都不会再弹出了,除非你再应用设置中进行打开。


到这一步,弹窗就出现了。


四、弹窗的开关


既然是增加用户的体验,那么自然要让用户可以自行控制,于是,我在新增了一个应用设置页面。在ui包下新建一个Empty Activity。命名为SettingActivity。它的xml布局如下:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    android:fitsSystemWindows="true"
    android:background="@color/gray_white"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.SettingActivity">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/white"
        app:contentInsetLeft="@dimen/dp_16"
        android:elevation="@dimen/dp_10"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_scrollFlags="scroll|enterAlways"
        app:navigationIcon="@mipmap/icon_return"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
        <!--标题-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="应用设置"
            android:textColor="@color/black"
            android:textSize="@dimen/sp_18" />
    </androidx.appcompat.widget.Toolbar>
    <!--每日一图-->
    <LinearLayout
        android:layout_marginTop="@dimen/dp_12"
        android:background="@color/white"
        android:paddingLeft="@dimen/dp_16"
        android:paddingRight="@dimen/dp_16"
        android:paddingTop="@dimen/dp_8"
        android:paddingBottom="@dimen/dp_8"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:text="每日弹窗"
            android:textColor="@color/black"
            android:textSize="@dimen/sp_16"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>
        <com.llw.mvplibrary.view.SwitchButton
            android:id="@+id/wb_everyday"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</LinearLayout>


整体来看这个页面目前只有一个管理每日弹窗的功能,有些孤独,不过后续我可能会加入其他的一些功能,敬请期待。


下面进入SettingActivity。里面的代码如下:


package com.llw.goodweather.ui;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import com.llw.goodweather.R;
import com.llw.goodweather.utils.Constant;
import com.llw.goodweather.utils.SPUtils;
import com.llw.goodweather.utils.StatusBarUtil;
import com.llw.mvplibrary.base.BaseActivity;
import com.llw.mvplibrary.view.SwitchButton;
import org.litepal.util.Const;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
 * 应用设置页面
 *
 * @author llw
 */
public class SettingActivity extends BaseActivity {
    @BindView(R.id.toolbar)
    Toolbar toolbar;
    @BindView(R.id.wb_everyday)
    SwitchButton wbEveryday;
    @Override
    public void initData(Bundle savedInstanceState) {
        //白色状态栏
        StatusBarUtil.setStatusBarColor(context, R.color.white);
        //黑色字体
        StatusBarUtil.StatusBarLightMode(context);
        Back(toolbar);
        boolean isChecked = SPUtils.getBoolean(Constant.EVERYDAY_POP_BOOLEAN,true,context);
        wbEveryday.setChecked(isChecked);
        wbEveryday.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(SwitchButton view, boolean isChecked) {
                if(isChecked){
                    SPUtils.putBoolean(Constant.EVERYDAY_POP_BOOLEAN,true,context);
                }else {
                    SPUtils.putBoolean(Constant.EVERYDAY_POP_BOOLEAN,false,context);
                }
            }
        });
    }
    @Override
    public int getLayoutId() {
        return R.layout.activity_setting;
    }
}


就是通过控件改变缓存值,一语中的。


然后就是在window_add.xml中增加一个TextView


    <TextView
            android:id="@+id/tv_setting"
            android:gravity="center"
            android:layout_width="@dimen/dp_140"
            android:layout_height="@dimen/dp_48"
            android:text="应用设置"
            android:foreground="@drawable/bg_white"
            android:textColor="@color/black"
            android:textSize="@dimen/sp_16"/>


如下图所示


20201204165028219.png


然后进入到MainActivity,在showAddWindow方法中。


绑定视图id

20201204165145843.png


增加点击跳转事件


20201204165228125.png


然后代码就写完了,是不是一气呵成呢?运行效果图如下:


20201204165427830.gif


这个GIF,之前我是为了测试所以没有加上每日第一次打开的限制,你只要按照博客来写就可以了。


文末


  来者可追,文过饰非。写博客和写代码的思路都要清晰才行,还是要加油,菜鸟多飞,山高水长,后会有期~

相关文章
|
2月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
225 0
安卓项目:app注册/登录界面设计
|
3月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
298 2
|
3月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
129 3
|
2月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
391 0
|
3月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
2月前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
738 7
|
2月前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
770 1
|
5天前
|
JSON 缓存 前端开发
HarmonyOS NEXT 5.0鸿蒙开发一套影院APP(附带源码)
本项目基于HarmonyOS NEXT 5.0开发了一款影院应用程序,主要实现了电影和影院信息的展示功能。应用包括首页、电影列表、影院列表等模块。首页包含轮播图与正在热映及即将上映的电影切换显示;电影列表模块通过API获取电影数据并以网格形式展示,用户可以查看电影详情;影院列表则允许用户选择城市后查看对应影院信息,并支持城市选择弹窗。此外,项目中还集成了Axios用于网络请求,并进行了二次封装以简化接口调用流程,同时添加了请求和响应拦截器来处理通用逻辑。整体代码结构清晰,使用了组件化开发方式,便于维护和扩展。 该简介概括了提供的内容,但请注意实际开发中还需考虑UI优化、性能提升等方面的工作。
49 11
|
3天前
|
前端开发 数据库 UED
uniapp开发,前后端分离的陪玩系统优势,陪玩app功能特点,线上聊天线下陪玩,只要4800
前后端分离的陪玩系统将前端(用户界面)和后端(服务器逻辑)分开开发,前者负责页面渲染与用户交互,后者处理数据并提供接口。该架构提高开发效率、优化用户体验、增强可扩展性和稳定性,降低维护成本,提升安全性。玩家可发布陪玩需求,陪玩人员发布服务信息,支持在线聊天、预约及线下陪玩功能,满足多样化需求。[演示链接](https://www.51duoke.cn/games/?id=7)
|
9天前
|
供应链 搜索推荐 API
1688APP原数据API接口的开发、应用与收益(一篇文章全明白)
1688作为全球知名的B2B电商平台,通过开放的原数据API接口,为开发者提供了丰富的数据资源,涵盖商品信息、交易数据、店铺信息、物流信息和用户信息等。本文将深入探讨1688 APP原数据API接口的开发、应用及其带来的商业收益,包括提升流量、优化库存管理、增强用户体验等方面。
56 6