常駐通知欄
Notification
//使用Notification欺抗,需要注意在android8.0以上的系統(tǒng)中尸折,需要定義channel,否則無法顯示通知
mBuilder = new NotificationCompat.Builder(this, CHANNEL_TOOLS);
mBuilder.setSmallIcon(R.drawable.ic_notification); // 設(shè)置頂部圖標(biāo)(狀態(tài)欄)
//需要實(shí)現(xiàn)自定義的布局狐援,需要實(shí)現(xiàn)RemoteView俱恶,通過setContent()方法設(shè)置
mBuilder.setContent(remoteViews);
注意點(diǎn):
1. 布局盡量不要限制死高度,在不同的Room下高度過大可能導(dǎo)致View超出通知框范圍
2. 布局背景顏色需要考慮庸毫,盡量使用透明背景色仔拟,同時(shí)布局內(nèi)其他組件也盡量保證在父布局透明時(shí)能夠保持正常視圖
3. 不能保證透明時(shí)較好的效果,則需要統(tǒng)一定死背景顏色飒赃,犧牲一定的room兼容(某些room獲取通知欄顏色不準(zhǔn)利花,會(huì)影響動(dòng)態(tài)設(shè)置背景色)
RemoteView
自定義通知欄中,需要自定義通知欄的視圖時(shí)载佳,需要使用RemoteView定義視圖晋被,代碼示例
//定義RemoteView視圖
RemoteView remoteViews = new RemoteViews(getPackageName(), R.layout.layout_tools_unit_normal_white);
//需要注意,在RemoteView中使用的空間有比較嚴(yán)格的限制刚盈,僅支持有限的幾種控件
//支持控件:
//布局
FrameLayout羡洛,LinearLayout,RelativeLayout,GridLayout
//控件
AnalogClock欲侮,Button崭闲,Chronometer,ImageButton威蕉,ImageView刁俭,ProgressBar,TextView韧涨,ViewFlipper牍戚,ListView,GridView虑粥,StackView如孝,AdapterViewFlipper,ViewStub
注意點(diǎn)
1. 在RemoteView中自定義控件是莫得用的
2. 在RemoteView中沒法直接拿到子View對(duì)象(可以通過方法操控)
RemoteView內(nèi)的控件無法直接通過findViewById來獲取娩贷,所以控制RemoteView中的組件需要通過提供的方法:
例如:
setTextViewText(int viewId, CharSequence text)
setImageViewResourse(int viewId, int resId)
setTextColor(int viewId, int color)
//實(shí)際上這一些方法的實(shí)現(xiàn)機(jī)制是通過反射完成的第晰,所有RemoteView的子組件都通過RemoteView調(diào)用提供的方法來操作
常駐效果
//常駐效果可以通過這行代碼實(shí)現(xiàn)
mBuilder.setOngoing(true);
小部件
小部件是可以單獨(dú)在桌面顯示的內(nèi)容,本質(zhì)上AppWidget實(shí)現(xiàn)的是一個(gè)廣播(BroadCastReceiver)彬祖,生成一個(gè)小部件會(huì)通知我們對(duì)AppWidget的定義茁瘦,然后生成相應(yīng)的布局以及內(nèi)容
定義小部件主體
實(shí)現(xiàn)小部件:繼承AppWidgetProvider
public class MyAgentWidget extends AppWidgetProvider {
/*
* 核心方法,在更新的時(shí)候調(diào)用
*/
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
//appWidgetManager:主要用來調(diào)用updataAppWidget(int appwidgetId, RemoteView view)
//這一方法用來替換刷新appwidgetId對(duì)應(yīng)的小部件的布局顯示储笑,通過RemoteView控制布局內(nèi)容
//AppWidget裝載內(nèi)容同樣使用的是RemoteView甜熔,所以RemoteView相關(guān)的限制在小部件上也一樣存在
//appWidgetIds:小部件定義完成以后,用戶可以在桌面生成多個(gè)相同的小部件突倍,所以一個(gè)小部件update()中對(duì)應(yīng)的id會(huì)是數(shù)組類型的數(shù)據(jù)
}
public void onEnable(Context context) {
//小部件首次添加到桌面時(shí)調(diào)用
}
public void onDisable(Context context) {
//小部件移除桌面時(shí)調(diào)用
}
}
AppWidgetManager的實(shí)例可以通過getInstance()來獲取纺非,在非Widget定義部分的代碼也可以對(duì)小部件的內(nèi)容進(jìn)行修改
//將RemoteView設(shè)置給指定的小部件替換為新的布局樣式
AppWidgetManager.getInstance().updateAppWidget(new ComponentName(Context, 小部件.class), RemoteView)
小部件注冊
小部件本體是一個(gè)BroadCastReceiver,那么對(duì)應(yīng)的在AndroidMainfest里要進(jìn)行注冊
<receiver android:name=".appwidget.MyAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
<!-- resource指向的xml文件是對(duì)Widget的一些基本定義 -->
android:resource="@xml/msg_widget_mine" />
</receiver>
小部件定義
在xml文件夾下赘方,
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/agent_tool_widget" <!-- 初始定義鎖屏頁面中布局 -->
android:initialLayout="@layout/agent_tool_widget" <!-- 初始定義桌面中布局 -->
android:minHeight="40dp" <!-- 布局最小高度 -->
android:minWidth="250dp" <!-- 布局最小寬度 -->
android:previewImage="@mipmap/ic_tools" <!-- 在選擇小部件時(shí)展示的圖片 -->
android:updatePeriodMillis="86400000" <!-- 更新時(shí)間毫秒值 -->
android:widgetCategory="home_screen"></appwidget-provider> <!-- 相當(dāng)于一個(gè)類別小部件的標(biāo)識(shí) -->
需要注意的是:通常定義下,桌面中的一格弱左,寬高都是40dp窄陡,但在不同的room下表現(xiàn)都會(huì)有差別(部分系統(tǒng)會(huì)在邊界添加padding),所以整體父布局盡量避免使用padding拆火,保持和桌面應(yīng)用的入口相似跳夭。
只占單格的小部件樣式為了更好的適配,最好只用一張圖片展示
快捷方式
快捷方式的實(shí)現(xiàn)和小部件原理相似们镜,同樣是發(fā)送廣播生成币叹;廣播發(fā)送后由系統(tǒng)接收,之后根據(jù)廣播中包含的內(nèi)容生成快捷方式模狭;
權(quán)限申請
<!-- 快捷方式生成 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 快捷方式移除 -->
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<!-- 快捷方式讀取信息 -->
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
生成快捷方式
ShortcutInfoCompat info = new ShortcutInfoCompat(Context context, String title)
.setIcon(快捷方式圖標(biāo)(Bitmap,IconCompat,Drawable))
.setShortLabel(String title)
.setIntent(點(diǎn)擊快捷方式發(fā)出的Intent)
.build();
//生成制定快捷方式
PendingIntent shortcutCallbackIntent = PendingIntent.getBroadCast(Context context, int type:快捷方式的唯一標(biāo)識(shí), Intent intent, PendingIntent.FLAG_UPDATE_CURRENT)
ShortcutManagerCompat.requestPinShortcut(Context context, ShortcutInfoCompat info, IntentSender intentSender)
快捷方式點(diǎn)擊
Intnet intent = new Intent(Context context, Class clazz);
intent.setAction(Intent.ACTION_VIEW); //必須設(shè)置項(xiàng)颈抚,缺失會(huì)導(dǎo)致崩潰
在首頁點(diǎn)擊快捷方式后將會(huì)直接根據(jù)Intent的內(nèi)容進(jìn)行相應(yīng)的跳轉(zhuǎn),此處的Intent可以設(shè)置FLAG來控制Activity的啟動(dòng)模式
關(guān)于PendingIntent的點(diǎn)擊效果
在RemoteView中要申明點(diǎn)擊事件需要借助PendingIntent來完成嚼鹉,但是有非常重要的一點(diǎn)在于贩汉,PendingIntent中申明的Flag是沒有效果的驱富,也就是說需要跳轉(zhuǎn)到首頁之類的頁面時(shí),在Intent中指定的啟動(dòng)模式是不會(huì)起到作用的匹舞;
如果原先的首頁是standard模式(一般都設(shè)置為這個(gè)模式)褐鸥,那么就會(huì)在跳轉(zhuǎn)是創(chuàng)建一個(gè)新的首頁(emm....),而修改首頁的launchMode也并不可取赐稽,會(huì)影響到切置后臺(tái)再從圖標(biāo)進(jìn)入時(shí)的邏輯叫榕;
對(duì)于RemoteView的點(diǎn)擊目標(biāo)最好不要直接跳轉(zhuǎn)到首頁,如果有必須跳轉(zhuǎn)的情況姊舵,這時(shí)就需要一個(gè)中轉(zhuǎn)頁面來輔助跳轉(zhuǎn)晰绎,因?yàn)镻endingIntent無法傳遞launchMode,所以需要先跳轉(zhuǎn)至中轉(zhuǎn)頁蠢莺,再由中轉(zhuǎn)頁通過Intent來定義launchMode寒匙,通過這種方式可以做到正確的跳轉(zhuǎn)