本系列文章将开始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源码解析