Android 天氣APP(三十一)每日提醒彈窗

語言: CN / TW / HK

我正在參加「掘金·啟航計劃」

效果圖

在這裡插入圖片描述


前言

  為了增強使用者的體驗,所以增加了這個每日彈窗,每日彈窗顧名思義,每天彈出一次,就不再彈窗,當然如果使用者覺得煩的話,可以在彈窗中勾選上不再彈窗,或者在應用設定中,關閉每日彈窗都是可以的。下面來寫這個功能。


正文

  說到彈窗我就想起來我之前的應用更新彈窗那一篇文章了,那麼這個功能怎麼來寫呢?其實也不難,首先想清楚這個彈窗要什麼東西。

① 是彈窗的背景,我希望每一天都不一樣,那麼就可以採用必應的每日一圖。 ② 彈窗可關閉不再彈出,可以通過快取的方式判斷處理, ③ 彈窗上面顯示的值,可以通過主頁面其它介面先獲取到返回值,然後在彈窗中顯示, ④ 每日只彈出一次,這個就是要在每日彈出彈窗時,儲存一個時間戳快取,後面再進入APP時判斷時間大小就可以了。

這麼一看,目標就明確了,下面進入實操環節。

一、彈窗背景

  還記得之前我在寫桌布頁面的時候,把必應的請求放到桌布管理頁面了,那麼主頁面就沒有請求了,而我又需要這個請求獲取每日的桌布url。所以在歡迎頁面新增了一個請求。

開啟SplashContract,新增如下程式碼:

```java /* * 獲取必應 每日一圖 / public void biying() { ApiService service = ServiceGenerator.createService(ApiService.class, 1); service.biying().enqueue(new NetCallBack() { @Override public void onSuccess(Call call, Response response) { if (getView() != null) { getView().getBiYingResult(response); } }

            @Override
            public void onFailed() {
                if (getView() != null) {
                    getView().getDataFailed();
                }
            }
        });
    }

```

java /** * 獲取必應每日一圖返回 * @param response BiYingImgResponse */ void getBiYingResult(Response<BiYingImgResponse> response);

增加位置如下: 在這裡插入圖片描述

然後進入SplashActivity,重寫getBiYingResult方法,程式碼如下:

```java /* * 必應桌布資料返回 * * @param response BiYingImgResponse / @Override public void getBiYingResult(Response 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中去建立。

```java /* * 每日提示彈窗的背景圖 / public static final String EVERYDAY_TIP_IMG = "everydayTipImg";

/**
 * 每日提示彈窗是否彈出
 */
public static final String EVERYDAY_POP_BOOLEAN = "everydayPopBoolean";

``` 在Constant裡面增加這兩個系統變數,註釋已經說明了這兩個變數的用途了。

下面在layout中新建一個dialog_everyday_tip.xml。裡面的程式碼如下: ```java

<!--彈窗背景圖-->
<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" />

```

預覽圖如下所示(==裡面的圖示沒有的話可以去我的原始碼裡面下載,或者自行下載一個,因為是白色的所示我貼了也看不見,CSDN中,不開會員的人無法修改文章的主題顏色,免費的主題,改不了博文的顏色,這一點我覺得很坑,非要你開個會員,吃相太難看了==) 在這裡插入圖片描述

這裡面用到了一個style,在app的styles.xml中增加如下程式碼:

css <!-- 圓角圖片 --> <style name="roundedImageStyle"> <item name="cornerFamily">rounded</item> <item name="cornerSize">12dp</item> </style>

在drawable下新建一個shape_dialog_foreground_bg_12.xml檔案,程式碼如下:

```css

``` 在app的colors.xml中新增一個顏色

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

佈局有了,那麼就是先改變背景,再增加資料。

二、每天第一次彈窗

下面進入到MainActivity中,將檢查版本更新的方法移動一個位置 在這裡插入圖片描述 因為自動更新的彈窗也是在每日第一次才彈出,所以公用,不過也要修改一下checkAppVersion裡面的邏輯才行。修改後程式碼如下:

```java /* * 檢查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方法了

java /** * 設定每日彈窗 */ 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); } } 這裡用到那麼那個系統變數,判斷是否可以彈窗這個彈窗,然後延時彈出。

三、彈出每日提示彈窗

```java /* * 每日提示彈窗 / 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佈局如下:

```css

<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>

``` 整體來看這個頁面目前只有一個管理每日彈窗的功能,有些孤獨,不過後續我可能會加入其他的一些功能,敬請期待。

下面進入SettingActivity。裡面的程式碼如下:

```java 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 css <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"/> 如下圖所示 在這裡插入圖片描述 然後進入到MainActivity,在showAddWindow方法中。

繫結檢視id

在這裡插入圖片描述 增加點選跳轉事件

在這裡插入圖片描述 然後程式碼就寫完了,是不是一氣呵成呢?執行效果圖如下: 在這裡插入圖片描述

這個GIF,之前我是為了測試所以沒有加上每日第一次開啟的限制,你只要按照部落格來寫就可以了。


文末

  來者可追,文過飾非。寫部落格和寫程式碼的思路都要清晰才行,還是要加油,菜鳥多飛,山高水長,後會有期~

原始碼地址:GoodWeather 歡迎 StarFork