一、Launcher加載佈局的基本流程
Launcher界面的內容展現是由default_workspace.xml決定的,它決定了每個屏幕顯示的內容和佈局.位於res\xml目錄下.它是在LauncherProvider裏的loadDefaultFavoritesIfNecessary方法進行解析,然後存儲到數據庫中.LauncherProvider繼承自ContentProvider.看下這個loadDefaultFavoritesIfNecessary方法.
synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId) {
String spKey = LauncherAppState.getSharedPreferencesKey();
//獲取SharedPreferences實例
SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
//初始化workspaceResId
int workspaceResId = origWorkspaceResId;
// 如果沒有提供就使用默認的佈局
if (workspaceResId == 0) {
workspaceResId = sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, R.xml.default_workspace);
}
// Populate favorites table with initial favorites
SharedPreferences.Editor editor = sp.edit();
editor.remove(EMPTY_DATABASE_CREATED);
if (origWorkspaceResId != 0) {
editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId);
}
//解析佈局數據,加載到數據庫中
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId);
mOpenHelper.setFlagJustLoadedOldDb();
editor.commit();
}
}
這個方法裏先初始化WorkSpaceId,然後作爲參數傳遞到loadFavorites中,在loadFavorites方法裏進行佈局的的解析,然後保存數據到數據庫中.代碼我就不貼了,有點多.
那麼Launcher是如何加載這個佈局的呢,Launcher是調用LauncherModel的startLoader方法實現的.
if (!mRestoring) {
if (sPausedFromUserAction) {
// If the user leaves launcher, then we should just load items
// asynchronously when
// they return.
mModel.startLoader(true, -1);
} else {
// We only load the page synchronously if the user rotates (or
// triggers a
// configuration change) while launcher is in the foreground
mModel.startLoader(true, mWorkspace.getCurrentPage());
}
}
LauncherModel是數據庫的操作類,在這個類里加載數據.
二、Launcher佈局分析
1.修改界面
default_workspace.xml如下
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
<!-- Far-left screen [0] -->
<!-- Left screen [1] -->
<appwidget
launcher:packageName="com.android.settings"
launcher:className="com.android.settings.widget.SettingsAppWidgetProvider"
launcher:screen="1"
launcher:x="0"
launcher:y="3"
launcher:spanX="4"
launcher:spanY="1" />
<!-- Middle screen [2] -->
<appwidget
launcher:packageName="com.android.deskclock"
launcher:className="com.android.alarmclock.AnalogAppWidgetProvider"
launcher:screen="1"
launcher:x="1"
launcher:y="0"
launcher:spanX="2"
launcher:spanY="2" />
<favorite
launcher:packageName="com.android.camera"
launcher:className="com.android.camera.Camera"
launcher:screen="2"
launcher:x="0"
launcher:y="3" />
<!-- Right screen [3] -->
<favorite
launcher:packageName="com.android.gallery3d"
launcher:className="com.android.gallery3d.app.Gallery"
launcher:screen="3"
launcher:x="1"
launcher:y="3" />
<favorite
launcher:packageName="com.android.settings"
launcher:className="com.android.settings.Settings"
launcher:screen="3"
launcher:x="2"
launcher:y="3" />
<!-- Far-right screen [4] -->
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
<favorite
launcher:packageName="com.android.dialer"
launcher:className="com.android.dialer.DialtactsActivity"
launcher:container="-101"
launcher:screen="0"
launcher:x="0"
launcher:y="0" />
<favorite
launcher:packageName="com.android.contacts"
launcher:className="com.android.contacts.activities.PeopleActivity"
launcher:container="-101"
launcher:screen="1"
launcher:x="1"
launcher:y="0" />
<favorite
launcher:packageName="com.android.mms"
launcher:className="com.android.mms.ui.ConversationList"
launcher:container="-101"
launcher:screen="3"
launcher:x="3"
launcher:y="0" />
<favorite
launcher:packageName="com.android.browser"
launcher:className="com.android.browser.BrowserActivity"
launcher:container="-101"
launcher:screen="4"
launcher:x="4"
launcher:y="0" />
</favorites>
這裏有2個標籤,widget和favorite(快捷方式).先介紹widget每個屬性含義
favorite的
我們對着桌面的圖來分析吧.
中間是一個設置的widget,位於第一個屏幕,對應着佈局裏launcher:screen="1". launcher:x="0"代表橫座標爲0, launcher:y="3" 代表縱座標爲3.launcher:spanX="4" 代表橫向佔據了4個格子,launcher:spanY="1"代表縱向佔據了3個格子.
比如我現在把設置widget屏蔽掉
<!-- <appwidget
launcher:packageName="com.android.settings"
launcher:className="com.android.settings.widget.SettingsAppWidgetProvider"
launcher:screen="1"
launcher:x="0"
launcher:y="3"
launcher:spanX="4"
launcher:spanY="1" /> -->
看下效果,中間的widget沒了.
2.修改圖標
圖標的信息都保存在IconCache這個類中,具體點就是cacheLocked這個方法中.
private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,
HashMap<Object, CharSequence> labelCache) {
CacheEntry entry = mCache.get(componentName);
if (entry == null) {
entry = new CacheEntry();
mCache.put(componentName, entry);
ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
if (labelCache != null && labelCache.containsKey(key)) {
entry.title = labelCache.get(key).toString();
} else {
entry.title = info.loadLabel(mPackageManager).toString();
if (labelCache != null) {
labelCache.put(key, entry.title);
}
}
if (entry.title == null) {
entry.title = info.activityInfo.name;
}
entry.icon = Utilities.createIconBitmap(getFullResIcon(info), mContext);
}
return entry;
}
在這裏把快捷方式的圖標和名稱都保存在一個map中,叫CacheEntry,如果你想要修改某個應用的圖標,可以在這裏修改,比如我把電話的圖標換成手指的圖標
在方法里加上這段代碼
if(entry.title.equals("Phone")){
Bitmap mbBitmap=BitmapFactory.decodeResource(mContext.getResources(), R.drawable.hand);
entry.icon = mbBitmap;
}
看下效果
就這樣,你想換哪個圖標就換哪個圖標.
3.替換壁紙
Launcher3默認的壁紙是/data/data/com.android.launcher3/files/default.thumb.jpg.如下圖
把它導出來正是那張"蠟燭"的背景圖.
如果想要替換成自己想要的壁紙那麼在Launcher的oncreate方法加上如下代碼就行.
WallpaperManager mwallpaerManager = WallpaperManager.getInstance(this);
try {
mwallpaerManager.setResource(R.drawable.kebi);
} catch (IOException e) {
e.printStackTrace();
}
這裏我換成的是科比的壁紙,看下效果
在桌面上長按空白處會彈出選擇壁紙的選項,點擊會跳轉到WallpaperPickerActivity,在裏面會進行壁紙的設置.
如果你想固定壁紙,那麼把WorkSpace的updateOffset方法註釋掉就行了,這樣壁紙就不隨着屏幕滾動而滾動了
private void updateOffset(boolean force) {/*
if (mWaitingForUpdate || force) {
mWaitingForUpdate = false;
if (computeScrollOffset() && mWindowToken != null) {
try {
mWallpaperManager.setWallpaperOffsets(mWindowToken,
mWallpaperOffset.getCurrX(), 0.5f);
setWallpaperOffsetSteps();
} catch (IllegalArgumentException e) {
Log.e(TAG, "Error updating wallpaper offset: " + e);
}
}
}
*/}
4.修改滾動指示器
如果只是想簡單的修改滾動指示器的圖片,那很好辦,在PageIndicator類的PageMarkerResources方法裏修改即可.
public static class PageMarkerResources {
int activeId;
int inactiveId;
public PageMarkerResources() {
// activeId = R.drawable.ic_pageindicator_current;
// inactiveId = R.drawable.ic_pageindicator_default;
activeId = R.drawable.no;
inactiveId = R.drawable.yes;
}
public PageMarkerResources(int aId, int iaId) {
activeId = aId;
inactiveId = iaId;
}
}
我把它換成自定義的兩張圖片,一張紅色的,一張白色的,看下效果.
歡迎留言