首先,什麼是桌面widget,桌面widget是一種桌面插件,以下圖: android
這種類型的控件叫作widget,通常長按桌面會彈出一個界面讓你選擇控件,選擇完了拖到桌面就能使用了。git
下面咱們爲這個app來添加一個widget,先看一下效果吧。 github
而後點擊這個桌面widget,讓他跳轉到咱們的app裏面app
怎麼樣,效果還不錯吧?ide
下面重點講一下實現widget的主要步驟:
1. 在AndroidManifest.xml裏面定義聲明 AppWidgetProvider
2. 初始化AppWidget的xml文件(信息)
3. 實現AppWidget的佈局
4. 繼承 AppWidgetProvider 類,實現具體的 Widget 業務邏輯。
一、在AndroidManifest.xml
裏面定義聲明 AppWidgetProvider函數
<receiver android:name=".widget.RecyclerWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver>
<intent-filter>
中必需要包含 APPWIDGET_UPDATE
這個 <action>
,全部 Widget 的 broadcast 都是經過這個 filter 來接收的。<meta-data>
聲明瞭 Widget的xml 信息,用的是 xml 目錄下的 widget_info.xml。佈局
二、widget_info.xmlspa
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="250dp" android:minHeight="170dp" android:updatePeriodMillis="0" android:previewImage="@drawable/widget_preview" android:initialLayout="@layout/widget_layout" android:resizeMode="horizontal|vertical" android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
記住,這個文件不是widget的佈局,而是widget的信息,描述了widget的寬高、刷新時間等等信息。 minWidth & minHeight
:定義了 Widget 的最小寬高,當 minWidth 和 minHeight 不是桌面 cell 的整數倍時,Widget 的寬高會被闊至與其最接近的 cells 大小。Google 官方給出了一個大體估算 minWidth & minHeight 的公式,根據 Widget 所佔的 cell 數量來計算寬高:70 × n − 30,n 是所佔的 cell 數量。.net
updatePeriodMillis
: 定義了 Widget 的刷新頻率,也就是 App Widget Framework 多久請求一次 AppWidgetProvider 的 onUpdate() 回調函數。可是,系統默認最小更新時間是30分鐘,若是這裏定義的時間小於30分鐘,那麼刷新時間仍是30分鐘。插件
previewImage
:widget的預覽圖,就是咱們widget列表裏面那些預覽圖
initialLayout
: 這裏定義的纔是widget的佈局
resizeMode
:Widget 在水平和垂直方向是否能夠調整大小,值能夠爲:horizontal(水平方向能夠調整大小),vertical(垂直方向能夠調整大小),none(不能夠調整大小),也能夠 horizontal|vertical 組合表示水平和垂直方向都可以調整大小。
widgetCategory
:表示 Widget 能夠顯示的位置,包括 home_screen(桌面),keyboard(鎖屏),keyboard 屬性須要 5.0 或以上 Android 版本才能夠。
三、AppWidget的佈局
這裏佈局能夠隨便寫,我簡單的寫了個ImageView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/iv_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/widget_preview" android:layout_centerHorizontal="true"/> </RelativeLayout>
四、繼承 AppWidgetProvider
類
public class RecyclerWidgetProvider extends AppWidgetProvider { public RecyclerWidgetProvider() { super(); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); Log.i("shenlong", "onUpdate"); for (int i = 0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; Log.i("shenlong", "onUpdate appWidgetId=" + appWidgetId); Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME); intent.setClass(context, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); // Get the layout for the App Widget and attach an on-click listener // to the button RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); views.setOnClickPendingIntent(R.id.iv_widget, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app widget appWidgetManager.updateAppWidget(appWidgetId, views); } } /** * 當 Widget 被刪除時調用該方法。 * * @param context * @param appWidgetIds */ @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Toast.makeText(context, "onDeleted", Toast.LENGTH_SHORT).show(); } /** * 當 Widget 第一次被添加時調用,例如用戶添加了兩個你的 Widget,那麼只有在添加第一個 Widget 時該方法會被調用。 * 因此該方法比較適合執行你全部 Widgets 只需進行一次的操做 * * @param context */ @Override public void onEnabled(Context context) { super.onEnabled(context); } /** * 與 onEnabled 剛好相反,當你的最後一個 Widget 被刪除時調用該方法,因此這裏用來清理以前在 onEnabled() 中進行的操做。 * * @param context */ @Override public void onDisabled(Context context) { super.onDisabled(context); } /** * 當 Widget 第一次被添加或者大小發生變化時調用該方法,能夠在此控制 Widget 元素的顯示和隱藏。 * * @param context * @param appWidgetManager * @param appWidgetId * @param newOptions */ @Override public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); } @Override public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) { super.onRestored(context, oldWidgetIds, newWidgetIds); } }
註釋寫的應該還蠻詳細的, onUpdate
、onDeleted
、onDisabled
、onAppWidgetOptionsChanged
等函數的調用時機都寫在註釋裏了。另外,AppWidgetProvider
繼承自 BroadcastReceiver
,因此要實現onReceive()
方法, onReceive()
中處理的是 Widget 相關的廣播事件,而後分發到各個回調函數中onUpdate()
, onDeleted()
, onEnabled()
, onDisabled
, onAppWidgetOptionsChanged()
。
五、爲widget添加點擊事件
a、首先先定義個開啓Activity的intent
Intent intent = new Intent();
b、用intent實例化一個PendingIntent,調用pendingIntent的getActicity方法來啓動另外一個Activity
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
c、實例化RemoteView,其對應相應的Widget佈局
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
d、給RemoteView上的控件設置按鈕事件
views.setOnClickPendingIntent(R.id.iv_widget, pendingIntent);
e、更新AppWidget界面
appWidgetManager.updateAppWidget(appWidgetId, views);
這樣,就實現了點擊事件,效果圖能夠見上圖
源碼:https://github.com/AdleyLong/RecyclerViewDemo
轉: https://blog.csdn.net/Picasso_L/article/details/70597609