Android4.4-Launcher源碼分析系列之Launcher界面修改、壁紙替換、圖標替換、修改滾動指示器

一、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;
        }
    }
我把它換成自定義的兩張圖片,一張紅色的,一張白色的,看下效果.




歡迎留言


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章