編輯:關於Android編程
桌面小工具是可以放置在主界面的、快速控制應用的小助手。例如我們的音樂小工具,它可以幫助用戶在桌面上就完成音樂的暫停、播放、切換等操作,而不需要啟動應用本身。
在安卓系統中,我們也常常叫它App widget。
實現一個App widget要經過以下幾個步驟,
創建一個App widget類,讓它繼承自AppWidgetProvider,例如AnddleMusicAppWidget類; 放在res\layout目錄下,為App widget的界面定義一個布局,例如anddle_music_app_widget.xml; 在res\xml目錄下,定義一個App widget的說明文件,例如anddle_music_app_widget_info.xml 在AndroidManifest.xml文件當中,聲明App widget;對於使用Android Studio的用戶來說,完成上面四個步驟的方法非常簡單。因為Android Studio提供了簡單的可視化向導來幫助我們。
在項目工程上點擊右鍵,選擇new->Wideget->App Widget就為我們創建好了開發用的模版,非常的簡單方便。
在彈出的創建向導中,填上創建的參數,
給App widget取個名字-AnddleMusicAppWidget; 允許將App widget放到主界面上; 不允許App widget的顯示區域動態調整; App widget占用3格寬1格高;這些參數最後將反應在res/xml/anddle_music_app_widget.info.xml這個配置文件當中,
運行起來,就可以開始將App widget添加到桌面了。
現在,我們開始修改布局文件anddle_music_app_widget.xml,將App widget設計成如下的效果,
然後修改anddle_music_app_widget_info.xml的android:previewImage屬性,讓它指向的圖片變成預覽的效果圖,
AnddleMusicAppWidget類負責App widget的邏輯響應。
繼承AppWidgetProvider之後,開發者可以選擇的實現onUpdate() onAppWidgetOptionsChanged() onDeleted() onEnabled() onDisabled()和onRestored()等多個函數,
public class AnddleMusicAppWidget extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { } @Override public void onEnabled(Context context) { } @Override public void onDisabled(Context context) { } @Override public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { } @Override public void onDeleted(Context context, int[] appWidgetIds) { } @Override public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) { } }
桌面上可以同時添加多個相同的App widget,系統會為每個App widget分配一個id,以便將來更新它們或者對它們進行別的操作時,能夠正確的區分它們。
假設現在桌面上沒有我們音樂播放器對應的App widget,此時添加一個的話,會依次觸發,
onEnabled() onUpdate()
如果此時繼續添加,會接著觸發,
onUpdate()
如果系統要更新App widget的顯示,也會觸發,
onUpdate()
此時刪除一個,會觸發,
onDeleted()
此時再刪除最後一個,會觸發,
onDeleted() onDisabled()
當設備開機,會觸發,
onEnabled() onUpdate()
在App widget的設計框架中,每個顯示出來的小工具界面,叫做RemoteViews,它是由如下方式創建的,
//第二個參數就是桌面小工具的布局文件 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget);
然後由RemoteViews提供的設置方法,來設置界面上每個元素的樣子,比如某個TextView該顯示什麼文字,某個ImageView該顯示什麼圖片,某個Button被點擊後要觸發什麼操作等等。
然後,通過調用系統提供的AppWidgetManager.updateAppWidget(),將這個界面更新到App widget上面去,
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); //appWidgetId就是主界面上某個特定App widget的Id值,它會由onUpdate()函數傳入 appWidgetManager.updateAppWidget(appWidgetId, views);
所以AnddleMusicAppWidget要提供一個對外調用的接口,讓其它組件可以在需要的時候更新小工具界面。
前面提到了RemoteViews的創建方法。現在來詳細介紹下界面上每個元素的設置方式,比如某個TextView該顯示什麼文字,某個ImageView該顯示什麼圖片,某個Button被點擊後要觸發什麼操作等等。
如果創建RemoteViews的布局中有TextView控件,並需要設置內容,
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //設置id為R.id.music_name的TextView,顯示musicName代表的字符串 views.setTextViewText(R.id.music_name, musicName);
如果創建RemoteViews的布局中有ImageView控件,並需要設置圖片內容,
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //設置id為R.id.image_thumb的ImageView,顯示thumb代表的bitmap圖片 views.setImageViewBitmap(R.id.image_thumb, thumb);
除了上面提到的控件和屬性,控件的很多屬性並專門的設置函數。不過RemoteViews為我們引入了更加靈活的設置方式。例如要設置Button的background屬性,
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //設置id為R.id.image_thumb的Button,調用它的setBackgroundResource()函數, //傳入R.mipmap.ic_pause參數,相當於調用了Button的setBackgroundResource(R.mipmap.ic_pause) views.setInt(R.id.play_btn2, "setBackgroundResource", R.mipmap.ic_pause);
如果創建RemoteViews的布局中有Button控件,為它添加點擊響應,
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //用隱士調用的方法-指定Action-創建一個Intent Intent preIntent = new Intent(MusicService.ACTION_PLAY_MUSIC_PRE); //設置響應的組件名稱 preIntent.setComponent(serviceName); //將Intent轉化成PendingIntent PendingIntent prePendingIntent = PendingIntent.getService(context, 0, preIntent, 0); //設置id為R.id.pre_btn2的Button,設計點擊後要觸發的PendingIntent views.setOnClickPendingIntent(R.id.pre_btn2, prePendingIntent);
RemoteViews不能直接設置按鈕點擊後的操作,必須通過設置PendingIntent來實現。所以要在響應的模塊中添加響應的邏輯。
繼承AppWidgetProvider,准備實現onUpdate()函數,並提供performUpdates()的靜態函數作為其它組件刷新界面的接口,搭建的代碼結構如下,
public class AnddleMusicAppWidget extends AppWidgetProvider { //保存各個小工具的id private static int [] sAppWidgetIds; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { //保存各個小工具的id,以備將來其它組件調用performUpdates()接口時能用到 sAppWidgetIds = appWidgetIds; //更新小工具的界面 performUpdates(context, context.getString(R.string.no_song), false, null); } //對外提供的更新所有小工具的界面接口,需要傳入音樂的名稱、當前是否播放、音樂封面等參數 public static void performUpdates(Context context, String musicName, boolean isPlaying, Bitmap thumb) { //如果沒有小工具的id,就沒法更新界面 if(sAppWidgetIds == null || sAppWidgetIds.length == 0) { return; } AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); //遍歷每個桌面上的小工具,根據id逐個更新界面 for (int appWidgetId : sAppWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId, musicName, isPlaying, thumb); } } //更新指定id的小工具界面 private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, String musicName, boolean isPlaying, Bitmap thumb) { //創建RemoteViews RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //添加界面元素的邏輯控制代碼,例如按鈕、文字、圖片等等 ...... //通過appWidgetId,為指定的小工具界面更新 appWidgetManager.updateAppWidget(appWidgetId, views); } ...... }
實現對界面元素的邏輯控制,
“`java
public class AnddleMusicAppWidget extends AppWidgetProvider {
...... //更新指定id的小工具界面 private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, String musicName, boolean isPlaying, Bitmap thumb) { //創建RemoteViews RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.anddle_music_app_widget); //添加界面元素的邏輯控制代碼,例如按鈕、文字、圖片等等 //設置音樂的名稱 views.setTextViewText(R.id.music_name, musicName); //設置按鈕響應的對象,這裡是MusicService final ComponentName serviceName = new ComponentName(context, MusicService.class); //設置下一首按鈕對應的PendingIntent //通過MusicService.ACTION_PLAY_MUSIC_NEXT定義隱性Intent,喚醒MusicService的響應 Intent nextIntent = new Intent(MusicService.ACTION_PLAY_MUSIC_NEXT); nextIntent.setComponent(serviceName); PendingIntent nextPendingIntent = PendingIntent.getService(context, 0, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.next_btn2, nextPendingIntent); //設置前一首按鈕對應的PendingIntent //通過MusicService.ACTION_PLAY_MUSIC_PRE定義隱性Intent,喚醒MusicService的響應 Intent preIntent = new Intent(MusicService.ACTION_PLAY_MUSIC_PRE); preIntent.setComponent(serviceName); PendingIntent prePendingIntent = PendingIntent.getService(context, 0, preIntent, 0); views.setOnClickPendingIntent(R.id.pre_btn2, prePendingIntent); //設置播放暫停按鈕對應的PendingIntent //通過MusicService.ACTION_PLAY_MUSIC_TOGGLE定義隱性Intent,喚醒MusicService的響應 Intent toggleIntent = new Intent(MusicService.ACTION_PLAY_MUSIC_TOGGLE); toggleIntent.setComponent(serviceName); PendingIntent togglePendingIntent = PendingIntent.getService(context, 0, toggleIntent, 0); views.setOnClickPendingIntent(R.id.play_btn2, togglePendingIntent); //設置播放暫停按鈕的圖標 views.setInt(R.id.play_btn2, "setBackgroundResource", isPlaying ? R.mipmap.ic_pause : R.mipmap.ic_play); //設置音樂的封面 if(thumb != null) { views.setImageViewBitmap(R.id.image_thumb, thumb); } else { views.setImageViewResource(R.id.image_thumb, R.mipmap.default_cover); } //通過appWidgetId,為指定的小工具界面更新 appWidgetManager.updateAppWidget(appWidgetId, views); } ......
}
近段時間來Android上最火的框架非react native莫屬了,這裡我不去評價這個框架的好壞,畢竟只有用過的人才會有深刻的體會。但是我個人有一個習慣,在使用一個開源
一、寫在最前面本次,來介紹一下安卓中為控件--Button綁定事件的五種方式。二、具體的實現第一種:直接綁定在Button控件上:步驟1.在Button控件上設置andr
最近自家的系統要做一個升級服務,裡面有三個功能,第一個是系統升級,也就是下載OTA包推送到recovery裡升級的,而第二個是MCU升級,這就涉及到我們自家系統的一些情況
前言在Android中,動畫Animation的實現有兩種方式:Tween Animation(補間動畫)和Frame Animation(幀動畫)。漸變動畫是通過對場景