Launcher3 壁紙流程分析

Launcher3 壁紙分析

1. WallpaperPickerActivity結構

1.1 父類WallpaperCropActivity

WallpaperPickerActivity是WallpaperCropActivity的派生類。當前者執行onCreate()時,它會調用父類的onCreate(),在父類執行onCreate()時又會調用init(),而WallpaperPickerActivity複寫了init()方法,故又回到自己的init()中。 
圖1

1.2 佈局文件wallpaper_picker.xml

在init()方法中,對佈局文件wallpaper_picker.xml中的許多控件進行了初始化。以下是wallpaper_picker.xml的部分代碼。

<com.android.launcher3.WallpaperRootView
    android:id="@+id/wallpaper_root">
    <com.android.launcher3.CropView
        android:id="@+id/cropView"/>
    <ProgressBar
        android:id="@+id/loading"/>
    <LinearLayout
        android:id="@+id/wallpaper_strip">
        <View
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="@drawable/tile_shadow_top" />
        <HorizontalScrollView
            android:id="@+id/wallpaper_scroll_container">
            <LinearLayout android:id="@+id/master_wallpaper_list">
                <LinearLayout android:id="@+id/wallpaper_list"/>
                <LinearLayout android:id="@+id/live_wallpaper_list"/>
                <LinearLayout android:id="@+id/third_party_wallpaper_list"/>
            </LinearLayout>
        </HorizontalScrollView>
        <View
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="@drawable/tile_shadow_bottom" />
    </LinearLayout>
</com.android.launcher3.WallpaperRootView>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

com.Android.launcher3.CropView是一個自定義View,用於顯示壁紙大圖。 
HorizontalScrollView下面有一個LinearLayout,master_wallpaper_list,它又有兩個子Layout,wallpaper_list和live_wallpaper_list,third_party_wallpaper_list節點已經被移除。

佈局中各節點的位置如下圖所示:

圖2

在圖 2中,壁紙大圖對應的是CropView,常規壁紙對應wallpaper_list的LinearLayout,而動態壁紙則是live_wallpaper_list。

2. 初始化流程

2.1 加載壁紙列表

在init()方法中,系統壁紙和用戶從圖庫中選擇過的壁紙會被加載到視圖中,下列三小節會描述這三種壁紙的加載過程。

2.1.1 系統壁紙

在init()中,先從findBundledWallpapers()中獲取一個WallpaperTileInfo類型的ArrayList。在findBundledWallpapers()中,需要從資源中獲取壁紙。根據/WallpaperPicker/res/values-nodpi/wallpapers.xml中的wallpapers數組,把壁紙資源生成WallpaperTileInfo對象加入到ArrayList中。

2.1.2 圖庫壁紙

用戶如果在圖庫中選擇過壁紙,那麼在init過程中,我們還要讀取那些用戶選擇的壁紙,並把它們加入到壁紙圖塊列表中。

mSavedImages是一個SavedWallpaperImages對象,該類時BaseAdapter的派生類,在loadThumbnailsAndImageIdList()方法中,把壁紙從數據庫中加載到Adapter中,然後再通過。populateWallpapersFromAdapter()方法把圖片列表加入到父佈局中。

mSavedImages = new SavedWallpaperImages(this);
mSavedImages.loadThumbnailsAndImageIdList();
populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.1.3 動態壁紙

動態壁紙的加載方式與前兩種壁紙稍有區別。因爲加載動態壁紙所需要的時間更長,所以對LiveWallpaperListAdapter對象註冊了DataSetObserver。在動態壁紙列表的數據加載完成時會調用DataSetObserver的onChanged()回調方法,把壁紙圖塊加入LinearLayout中。

2.2 加載圖庫壁紙按鍵

在上述幾種類型的壁紙加載完成後,列表中還要加載一個從圖庫中選擇壁紙的按鍵,這個按鍵是動態加入到LinearLayout中的,所以在wallpaper_picker不會出現。 
該按鍵的初始化代碼如下:

LinearLayout masterWallpaperList = (LinearLayout)findViewById(R.id.master_wallpaper_list);
FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);

mPickImageTile = pickImageTile;

setWallpaperItemPaddingToZero(pickImageTile);
masterWallpaperList.addView(pickImageTile, 0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到,該按鍵是以一個FrameLayout的形式加入到壁紙列表中的,與populateWallpapersFromAdapter()方法中的形式相同。 
該按鍵是一個CheckableFrameLayout,顧名思義,這種Layout是可以被點擊。它包含了一張圖片和一個TextView,具體的佈局文件是WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml。上面的代碼是把該佈局inflate進來作爲一個按鍵並加入到壁紙列表中。

2.3 Actionbar的初始化和響應

在壁紙的初始化過程中,ActionBar的樣式被改變了。通過調用actionBar.setCustomView(R.layout.actionbar_set_wallpaper),可以把自定義的佈局設置爲ActionBar的視圖。該佈局中是一個AlphaDisableableButton,它重寫了View.setEnabled()方法。 
ActionBar的點擊事件是用於確認當前選擇壁紙的。在點擊ActionBar後,獲取當前選定的圖塊Info,嘗試將其設爲壁紙,並finish當前Activity,把結果傳回上一個Activity。

2.4 點擊事件

在描述點擊事件之前,首先看看一個抽象類,WallpaperTileInfo。這個類中有一個View,一個Drawable以及onClick(),onSave()等方法。WallpaperTileInfo有幾個派生類,如下圖所示: 
圖3

這些派生類在加載不同類別的壁紙時會有不同的實現。比如PickImageInfo,它代表上文中說到的加載圖庫壁紙按鍵的類型。它的onClick()方法中的實現是發一個Intent去打開DocumentsUI,挑選一張壁紙。其他派生類,如果是壁紙的話,onClick()方法中則會根據自己的壁紙信息,計算寬高和座標,把縮略圖對應的大圖設爲背景,這樣用戶就可以預覽壁紙效果。 
在初始化過程中,有一個專門用於壁紙列表的監聽器,mThumbnailOnClickListener。它的onClick()方法實現中有如下語句:

WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
if (info == null) {
    return;
}
if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
    selectTile(v);
}
info.onClick(WallpaperPickerActivity.this);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在前文中提到的populateWallpapersFromAdapter()方法中,所有壁紙圖塊,包括mPickImageTile,都將此listener作爲監聽器。這樣當他們被點擊時,會擁有自己的行爲

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