作者:生活簡單些
連結:https://www.jianshu.com/p/9a8fa0a3bc4c
App中的紅點廣泛用於提醒功能,雖然用在選單上、Tab上、串列,但本質它就是一個紅色的View,不就是放哪裡就顯示在哪裡嘛,有什麼難的?對!這是UI設計師和產品經理的一致觀點,但是作為開發你可別信了他們的鬼話!
這邊文章講紅點,絕不是講如何設計紅點的UI,而是講在程式碼層面如何實現,如何快速整合到業務中。如果你聽了UI設計師和產品的鬼話你可能就真的哪裡需要顯示紅點然後就在哪裡放紅點view了,然後透過外部程式碼控制它的隱藏和顯示,你會很累,要定義很多key-value來儲存記錄各種紅點顯示的條件,零零碎碎很分散,這根本不是統一的解決方案,這是典型的想到哪裡做到哪裡。
我的想法是建立一個紅點View,你可以將此紅點View放置在任何需要的View的右上方,然後初始化告知它顯示的條件,即:接收哪幾類通知提醒,比如告知它顯示的條件是App有版本提醒就結束了,條件滿足自動就會顯示,條件不滿足自動隱藏。
關於此紅點View的接入方式,非常簡單如下:
// 紅點提醒如果需要區分賬戶則需要設定賬戶,
// 比如:App升級提示無需區分賬戶,個人訊息提醒需要區分賬戶
mRedDotView.setAccount(accountId);
// 設定當前紅點監聽的appLinks,只有收到了設定的AppLink才會觸發當前紅點的顯示和隱藏
mRedDotView.setAppLinks("my-scheme://NewMsgAlert");
關於AppLink之前一篇文章提到過,本質就是藉助scheme定義的url解析規則,不同的AppLink對應不用的響應策略。
下麵我們分析下紅點顯示的特性:
-
相似而不相同性:都是紅點,只是不同位置的紅點關註的提示內容不一樣,所以更有必要定義統一規則來控制其顯示和隱藏,因此我們使用AppLink來統一解析和管理,不同的紅點View需要設定它所關註的AppLink,如上面接入方式所示,只要每個紅點View在初始化時候指定想要關註的AppLinks即可,如果需要賬戶隔離則別忘記設定account:
-
永續性:如果不點選、不檢視,它會一直顯示,哪怕App被殺掉再開啟。因此,紅點觸發的條件是儲存下來的,常見辦法是透過SharedPreference或Database,我採用了Database方式,因為可以便捷的透過SQL檢索以及資料統一管理,當紅點View載入後會在onAttachedToWindow()里根據註冊的AppLinks查詢是否有未讀的AppLinks:
public class PushMessageDbHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS push_message (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"title TEXT," +
"sub_title TEXT," +
"pic_url TEXT," +
"app_link TEXT," +
"account TEXT," +
"update_dt TEXT," +
"read INTEGER)");
}
// ... others
}
資料庫表結構定義,這是一個融合了AppLink、推送標題、子標題、推送通知圖片、賬戶ID、是否已讀等資訊的表定義。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
checkVisible();
// ...other code
}
當view載入成功後查詢之前有沒有未讀的AppLinks,如果有則設定紅點顯示。
-
即時性:紅點是否要顯示既可以是view初始化過程中查詢資料庫得知的,也可以是即時通知的,比如推送使得紅點顯示:
public class RedDotView extends AppCompatImageView {
private PushContentReceiver mContentReceiver = new PushContentReceiver() {
@Override
public String getAccount(@NonNull Context context) {
return mAccount;
}
@Override
public List getAppLinks() {
return mAppLinks;
}
@Override
public boolean onReceive(@NonNull Context context, @NonNull AppLink appLink) {
Log.d("DotView", "onReceive appLink: " + appLink);
if (mAppLinks == null || mAppLinks.size() == 0) {
return false;
}
boolean haveUnReadMsg = false;
for (String item : mAppLinks) {
if (PushMessageService.getInstance(getContext()).haveUnread(item, getAccount(context))) {
haveUnReadMsg = true;
break;
}
}
setVisibility(haveUnReadMsg ? VISIBLE : GONE);
return false;
}
};
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
PushContentReceiver.register(getContext(), mContentReceiver, false);
checkVisible();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
PushContentReceiver.unregister(getContext(), mContentReceiver);
}
// ...others code
}
由上可見在View的onAttachedToWindow()裡註冊了一個監聽AppLink的receiver。
需要註意的是這裡的AppLink在定義的時候需要註明它是需要儲存的,即overide shouldSave() 並傳回true告知此AppLink收到後要儲存在DB裡,因為即便App殺掉再次開啟還是需要顯示紅點的,如下案例:
public class NewMsgAlert extends AppLink {
@Override
public boolean isPrivate() {
return true;
}
@Override
public boolean shouldSave() {
return true;
}
}
總之,思路並不複雜,主要是充分發揮scheme設計的AppLink帶來的好處,關於此View的實現也很簡單,可以參考這裡。
https://github.com/daydream123/applink/blob/master/library/src/main/java/com/feizhang/applink/RedDotView.java
朋友會在“發現-看一看”看到你“在看”的內容