本系列文章將開始android lancher源碼分析,使用的例子是android 2.3中內建的launcher3源碼。其為http://download.csdn.net/detail/xianming01/4383598
在上一篇文章《android Launcher源碼解析01:UI布局詳解一》中,我們介紹了launcher3中的主題UI布局。這一篇我們將開始介紹其中的某個組成部分。
今天要介紹的是是擷取應用列表這一部分。
1、布局檔案
這一部分的介面顯示是這樣的:
其組成成分為一個應用列表和一個home按鈕。
在lancher的布局檔案launcher.xml中,關於應用列表的部分為:
<include layout="@layout/all_apps" />
這裡實際上是包含了all_apps.xml這個布局檔案,其內容為:
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <include layout="@layout/all_apps_2d" /></merge>
其作用是將all_apps_2d.xml這個布局檔案包含進來,其內容為:
<com.android.launcher3.AllApps2D xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/all_apps_view" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="2dip" > <GridView android:id="@+id/all_apps_2d_grid" android:tag="all_apps_2d_grid" android:scrollbars="none" android:drawSelectorOnTop="false" android:listSelector="@drawable/grid_selector" android:verticalSpacing="10dip" android:numColumns="6" android:fadingEdgeLength="48dip" android:cacheColorHint="#FF000000" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_marginRight="@dimen/button_bar_height_portrait" android:nextFocusRight="@+id/all_apps_2d_home" android:nextFocusUp="@null" android:nextFocusLeft="@null" android:nextFocusDown="@null" /> <view class="com.android.launcher3.AllApps2D$HomeButton" android:id="@+id/all_apps_2d_home" android:tag="all_apps_2d_home" android:src="@drawable/home_button" android:background="#FF000000" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_height="wrap_content" android:layout_width="@dimen/button_bar_height_portrait" android:paddingBottom="@dimen/status_bar_height" android:nextFocusLeft="@+id/all_apps_2d_grid" android:nextFocusDown="@null" android:nextFocusUp="@null" android:nextFocusRight="@null" /></com.android.launcher3.AllApps2D>
從上面我們可以看出,這一部分的實現是由一個gridview來顯示應用程式列表,而home按鈕則是一個view.
2、實現原理
在AllApps2D.java這個類中,我們可以看到這一部分的實現。實際上在本人的部落格《android
Launcher基礎知識》中有關於這一部分的簡單形式,有興趣的可以看一下,那個比較簡單.
在代碼中是如何?的呢?我們來找一下:
mHandleView = (HandleView) findViewById(R.id.all_apps_button); mHandleView.setLauncher(this); mHandleView.setOnClickListener(this); mHandleView.setOnLongClickListener(this);
再看onclick()方法:在onclick方法中,有一下代碼
else if (v == mHandleView) { if (isAllAppsVisible()) { closeAllApps(true); } else { showAllApps(true); }
我們再找一下showAllApps()方法
void showAllApps(boolean animated) { mAllAppsGrid.zoom(1.0f, animated); ((View) mAllAppsGrid).setFocusable(true); ((View) mAllAppsGrid).requestFocus(); // TODO: fade these two too mDeleteZone.setVisibility(View.GONE); mHandleView.setVisibility(View.GONE); mPreviousView.setVisibility(View.GONE); mNextView.setVisibility(View.GONE); hotseatLeft.setVisibility(View.GONE); hotseatRight.setVisibility(View.GONE); }
在上面用到了mAllAppsGrid,我們找一下這個控制項:
private AllAppsView mAllAppsGrid; mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view); mAllAppsGrid.setLauncher(this); mAllAppsGrid.setDragController(dragController); ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window. // Manage focusability manually since this thing is always visible ((View) mAllAppsGrid).setFocusable(false);
上面代碼是在Launcher.java中的setupview()方法中定義
all_apps_view是在all_app_2d.xml中定義。
你想找到AllApp2D.java中,可以找到mAllAppsGrid使用的方法,如addApps,removeApps,zoom這幾個方法:
public void addApps(ArrayList<ApplicationInfo> list) { // Log.d(TAG, "addApps: " + list.size() + " apps: " + list.toString()); final int N = list.size(); for (int i=0; i<N; i++) { final ApplicationInfo item = list.get(i); int index = Collections.binarySearch(mAllAppsList, item, LauncherModel.APP_NAME_COMPARATOR); if (index < 0) { index = -(index+1); } mAllAppsList.add(index, item); } mAppsAdapter.notifyDataSetChanged(); } public void removeApps(ArrayList<ApplicationInfo> list) { final int N = list.size(); for (int i=0; i<N; i++) { final ApplicationInfo item = list.get(i); int index = findAppByComponent(mAllAppsList, item); if (index >= 0) { mAllAppsList.remove(index); } else { Log.w(TAG, "couldn't find a match for item \"" + item + "\""); // Try to recover. This should keep us from crashing for now. } } mAppsAdapter.notifyDataSetChanged(); } public void zoom(float zoom, boolean animate) { // Log.d(TAG, "zooming " + ((zoom == 1.0) ? "open" : "closed")); cancelLongPress(); mZoom = zoom; if (isVisible()) { getParent().bringChildToFront(this); setVisibility(View.VISIBLE); mGrid.setAdapter(mAppsAdapter); if (animate) { startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_in)); } else { onAnimationEnd(); } } else { if (animate) { startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_out)); } else { onAnimationEnd(); } } }
在zoom()方法裡面有mGrid.setAdapter(mAppsAdapter),在構造方法中,給adapter已經賦值。
public AllApps2D(Context context, AttributeSet attrs) { super(context, attrs); setVisibility(View.GONE); setSoundEffectsEnabled(false); mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList); mAppsAdapter.setNotifyOnChange(false); }
那是如何擷取應用列表的呢?我們再回到Launcher.java中,在loadHotseats()中。由於該函數比較複雜,我們就不全顯示了,只顯示其中比較重要的部分:
PackageManager pm = getPackageManager(); ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
這樣就擷取了。下面以一個簡單的例子結束,擷取在sd卡中安裝的程式列表:
private void getSdcardApps(){ mSdcardAppsList.clear(); ActivityManager am = (ActivityManager)mLauncher.getSystemService(Activity.ACTIVITY_SERVICE); PackageManager pm =mLauncher.getPackageManager(); List<android.content.pm.ApplicationInfo> list = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES); for (android.content.pm.ApplicationInfo appInfo : list) { if((appInfo.flags & android.content.pm.ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0){ for (ApplicationInfo applicationInfo : mAllAppsList) { if(appInfo.packageName.equals(applicationInfo.componentName.getPackageName())){ mSdcardAppsList.add(applicationInfo); break; } } } } mAppsAdapter = new AppsAdapter(getContext(), mSdcardAppsList); mAppsAdapter.notifyDataSetChanged(); mGrid.setAdapter(mAppsAdapter); text.setVisibility(View.VISIBLE); text.setBackgroundResource(R.drawable.tab_mmenu_b3_normal); }
以上就是擷取應用列表的UI布局這一部分的解析。其中還涉及到一些重要的方面沒有解釋,比如在有的手機上可以通過上下滑動來查看app,有些確實通過左右翻頁來查看app,這個是如何?的?這個將在下一篇文章中介紹。
參考資料:
launcher修改--擷取應用列表launcher源碼解析