一寻仗、概念:
App Widget 即叫 應(yīng)用微件 或者 小組件/插件.
是可以嵌入其他應(yīng)用(如主屏幕)并 接收定期更新的微型應(yīng)用視圖。
這些視圖稱為界面中的微件.
例如,添加到桌面上的音樂Widget:
能夠容納其他應(yīng)用微件的應(yīng)用組件稱為 AppWidgetHost (應(yīng)用微件托管應(yīng)用)缤沦。
App 通過傳遞要顯示布局id 給RemoteViews, 即可以獲取Widget的實(shí)例對象.
官網(wǎng)介紹:
指南:https://developer.android.com/guide/topics/appwidgets
UI指南(更詳細(xì)): https://developer.android.com/develop/ui/views/appwidgets/overview
二、基礎(chǔ)知識
官網(wǎng)上的介紹順序有點(diǎn)難懂半醉,可以參考一下順序疚俱,方便理解.
要創(chuàng)建App Widget,大體需要以下三點(diǎn):
(1) 視圖布局
定義 Widget的布局 (xml)
注意:
這個布局需要添加到 RemoteViews缩多, 而 RemoteViews 是不支持 ConstraintLayout的.
支持:LinearLayout/FrameLayout/RelativeLayout/GridLayout, 以及TextView/Button等基礎(chǔ)控件(不支持他們的子類)
(2) AppWidgetProviderInfo 對象
將數(shù)據(jù)封裝在元素<appwidget-provider>里
描述App Widget的元數(shù)據(jù)(meta-data)呆奕,如布局、更新頻率和 AppWidgetProvider 類衬吆。
此對象應(yīng)在 XML 中定義 并且 要在 AndroidManifest.xml中聲明梁钾。
(3) AppWidgetProvider 類實(shí)現(xiàn)
定義了 基于廣播事件, 通知到 Widget 的方法。
會在更新逊抡、啟用姆泻、停用和刪除 Widget 時收到廣播零酪。
要在 AndroidManifest.xml中聲明。
App可以通過它操作RemoteViews拇勃,例如更新等
三四苇、使用流程
1. 創(chuàng)建Widget 內(nèi)容的 布局
/layout/widget_content.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/forward_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="這是一個測試的Widget內(nèi)容 點(diǎn)擊我快速使用 App 某個功能" />
</RelativeLayout>
2. 添加 AppWidgetProviderInfo 元數(shù)據(jù)
數(shù)據(jù)封裝在元素<appwidget-provider>里.
/xml/example_appwidget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/widget_content"
android:initialLayout="@layout/widget_content"
android:minHeight="110dp"
android:minWidth="180dp"
android:previewImage="@drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="0"
android:widgetCategory="home_screen">
</appwidget-provider>
其中,
(1) initialLayout 則表示 widget 顯示的內(nèi)容
(2) minWidth / minHeight 表示W(wǎng)idget默認(rèn)情況下方咆,占用的最小空間. (最小大小不得超過 4 x 4 單元格)
(3) previewImage 表示預(yù)覽圖片月腋,即用戶添加時展示的 (這里是example_appwidget_preview.png )
(4) resizeMode 指定可以按什么規(guī)則來調(diào)整大小 (“horizontal”、“vertical”和“none”)
(5) widgetCategory 是否可以顯示在主屏幕(home_screen) 和/或鎖定屏幕 (keyguard)
注:這個XML 文件將會在AndroidManifest 聲明 AppWidgetProvider組件時瓣赂,由meta-data引用
3. 使用 AppWidgetProvider 類
AppWidgetProvider 類擴(kuò)展了 BroadcastReceiver, 作為一個輔助類來處理應(yīng)用微件廣播榆骚。
僅接收與Widget有關(guān)的事件廣播,例如當(dāng)更新煌集、刪除妓肢、啟用和停用Widget時發(fā)出的廣播.
當(dāng)發(fā)生這些廣播事件時,AppWidgetProvider 會接收以下方法調(diào)用:
onUpdate()
onAppWidgetOptionsChanged()
onDeleted(Context, int[])
onEnabled(Context)
onDisabled(Context)
onReceive(Context, Intent)
最重要的是 onUpdate苫纤, 如果要處理任何用戶交互事件碉钠,都需要在此回調(diào)處理.
這里我們設(shè)置,點(diǎn)擊了Widget 后卷拘,跳轉(zhuǎn)到 ExampleActivity 里.
class ExampleAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
// Perform this loop procedure for each App Widget that belongs to this provider
appWidgetIds.forEach { appWidgetId ->
// Create an Intent to launch ExampleActivity
val pendingIntent: PendingIntent = Intent(context, ExampleActivity::class.java)
.let { intent ->
PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) // set flags to fix fatal when sdk >=31
}
// Get the layout for the App Widget and attach an on-click listener
// to the button
val views: RemoteViews = RemoteViews(
context.packageName,
R.layout.widget_content
).apply {
setOnClickPendingIntent(R.id.forward_button, pendingIntent)
}
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
其中放钦,
(1) appWidgetIds 是一個ID 數(shù)組,對應(yīng)每一添加到主屏幕的Widget實(shí)例.
(即:可以在主屏幕添加 多個Widget)
(2) 不同的Widget 實(shí)例恭金,updatePeriodMillis 更新周期表依照第一個Widget實(shí)例.
(3) pendingIntent 用于點(diǎn)擊Widget上的Button時,跳轉(zhuǎn)到ExampleActivity
注意:在SDK>=31 上褂策,需要設(shè)置 FLAG_IMMUTABLE. 否則會出現(xiàn)fatal error:Strongly consider using FLAG_IMMUTABLE...
(4) ExampleActivity 是一個簡單的Activity,
代碼:
class ExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_example)
}
}
activity_example 為布局資源横腿,僅顯示一個TextView
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ExampleActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show this From Widget!!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
4. 在AndroidManifest中聲明 AppWidgetProvider 并聲明 AppWidgetProviderInfo
<receiver android:name="ExampleAppWidgetProvider"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>
需要在清單中聲明后,才能在小組件設(shè)置里添加.
此處的聲明可以反推出來:
(1) App Widget的入口斤寂,其實(shí)依賴 <intent-filter>里聲明的action:android.appwidget.action.APPWIDGET_UPDATE
(2)猜測系統(tǒng)(Launcher) 將會遍歷所有的AndroidManifest, 然后找到有這個action所在的組件.
在用戶長按應(yīng)用圖標(biāo)時耿焊,可顯示應(yīng)用 自定義的組件。
(3)而這個自定義組件的內(nèi)容是 從 meta-data里的 "android.appwidget.provider" 讀取出來遍搞。
(4)后續(xù)罗侯,有小組件的事件,則是通知到它所聲明的receiver (這里是ExampleAppWidgetProvider)
至此溪猿,已經(jīng)完成所有钩杰,
運(yùn)行app即可體驗(yàn).
5. 效果圖如下:
(1)添加Widget
(2) 添加Widget時的 預(yù)覽圖
(3) Widget 顯示圖
(4) 點(diǎn)擊Widget的button 后則會跳轉(zhuǎn)的對應(yīng)的Activity