??App中的紅點廣泛用于提醒功能,雖然用在菜單上午衰、Tab上立宜、列表冒萄,但本質(zhì)它就是一個紅色的View,不就是放哪里就顯示在哪里嘛橙数,有什么難的尊流?對!這是UI設(shè)計師和產(chǎn)品經(jīng)理的一致觀點灯帮,但是作為開發(fā)你可別信了他們的鬼話崖技!
??這邊文章講紅點,絕不是講如何設(shè)計紅點的UI钟哥,而是講在代碼層面如何實現(xiàn)迎献,如何快速集成到業(yè)務(wù)中。如果你聽了UI設(shè)計師和產(chǎn)品的鬼話你可能就真的哪里需要顯示紅點然后就在哪里放紅點view了腻贰,然后通過外部代碼控制它的隱藏和顯示吁恍,你會很累,要定義很多key-value來存儲記錄各種紅點顯示的條件播演,零零碎碎很分散冀瓦,這根本不是統(tǒng)一的解決方案,這是典型的想到哪里做到哪里宾巍。
??我的想法是創(chuàng)建一個紅點View咕幻,你可以將此紅點View放置在任何需要的View的右上方,然后初始化告知它顯示的條件顶霞,即:接收哪幾類通知提醒肄程,比如告知它顯示的條件是App有版本提醒就結(jié)束了,條件滿足自動就會顯示选浑,條件不滿足自動隱藏蓝厌。
關(guān)于此紅點View的接入方式,非常簡單如下:
// 紅點提醒如果需要區(qū)分賬戶則需要設(shè)置賬戶古徒,
// 比如:App升級提示無需區(qū)分賬戶拓提,個人消息提醒需要區(qū)分賬戶
mRedDotView.setAccount(accountId);
// 設(shè)置當前紅點監(jiān)聽的appLinks,只有收到了設(shè)置的AppLink才會觸發(fā)當前紅點的顯示和隱藏
mRedDotView.setAppLinks("my-scheme://NewMsgAlert");
關(guān)于AppLink之前一篇文章提到過隧膘,本質(zhì)就是借助scheme定義的url解析規(guī)則代态,不同的AppLink對應(yīng)不用的響應(yīng)策略。
下面我們分析下紅點顯示的特性:
相似而不相同性:都是紅點疹吃,只是不同位置的紅點關(guān)注的提示內(nèi)容不一樣蹦疑,所以更有必要定義統(tǒng)一規(guī)則來控制其顯示和隱藏,因此我們使用AppLink來統(tǒng)一解析和管理萨驶,不同的紅點View需要設(shè)置它所關(guān)注的AppLink歉摧,如上面接入方式所示,只要每個紅點View在初始化時候指定想要關(guān)注的AppLinks即可,如果需要賬戶隔離則別忘記設(shè)置account:
持久性:如果不點擊叁温、不查看再悼,它會一直顯示,哪怕App被殺掉再打開膝但。因此冲九,紅點觸發(fā)的條件是存儲下來的,常見辦法是通過SharedPreference或Database锰镀,我采用了Database方式娘侍,因為可以便捷的通過SQL檢索以及數(shù)據(jù)統(tǒng)一管理咖刃,當紅點View加載后會在onAttachedToWindow()里根據(jù)注冊的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
}
數(shù)據(jù)庫表結(jié)構(gòu)定義泳炉,這是一個融合了AppLink、推送標題嚎杨、子標題花鹅、推送通知圖片、賬戶ID枫浙、是否已讀等信息的表定義刨肃。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
checkVisible();
// ...other code
}
當view加載成功后查詢之前有沒有未讀的AppLinks,如果有則設(shè)置紅點顯示箩帚。
- 即時性:紅點是否要顯示既可以是view初始化過程中查詢數(shù)據(jù)庫得知的真友,也可以是即時通知的,比如推送使得紅點顯示:
public class RedDotView extends AppCompatImageView {
private PushContentReceiver mContentReceiver = new PushContentReceiver() {
@Override
public String getAccount(@NonNull Context context) {
return mAccount;
}
@Override
public List<String> 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()里注冊了一個監(jiān)聽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;
}
}
??總之愈案,思路并不復(fù)雜,主要是充分發(fā)揮scheme設(shè)計的AppLink帶來的好處鹅搪,關(guān)于此View的實現(xiàn)也很簡單站绪,可以參考[這里](https://github.com/daydream123/applink/blob/master/library/src/main/java/com/feizhang/applink/RedDotView.java