最近接了一个开发车载导航上的android launcher的工作,Launcher源码比较多,而且里面应用了很多设计模式,要把它分析清楚要花不少精力,网上也有一些零碎的分析文章,不过关于修改的文章不多,就想到要把开发和修改的过程通过博客的方式记录下来,边开发边记录,等开发完之后,再回顾肯定有很大的成就感,好了,废话不多说,切入正题。

  我现在手头上的launcher的源码是基于android4.1的,其实4.0,4.1,4.2,乃至4.4的差距并不是很大,但是由于运行系统是4.1的,所以,最好还是基于4.1的版本来开发,由于原生的launcher(以后简称桌面好了,比Launcher打的快一点),今天的主要工作就是去掉原生桌面的某些东西(搜索栏目,竖条等),修改hotseat的排列方式。先来看看我的效果图吧(开发样机使用的是魅族MX,嘻嘻*-*):

android 桌面实现原理 安卓桌面工具开发_xml

 

    因为程序是用于车载导航仪的,所以界面和一般的手机界面差别较大。改动也比较大,不过对于Launcher的分析修改都是通用的,大家也将就着看下去吧。这里也放一下原生桌面的样子:

android 桌面实现原理 安卓桌面工具开发_android_02

 

接下来,我们就针对界面修改的地方做分析:

 

一、竖屏改横屏

这里其实没什么技术含量,就是修改manifest,找到android:screenOrientation这个属性,将其值修改为landscape即可

 

二、去除google search bar

因为是定制的车载导航需要的launcher,所以这个一直显示在顶栏的google search bar就显得比较讨厌了,肯定是要去掉的,那么,要怎么去掉呢,研究清楚了其实也不复杂:

1. Launcher2\res\layout\qsb_bar.xml中,

1     <include android:id="@+id/qsb_search_bar"
2         layout="@layout/search_bar"
3          android:visibility="gone"  />

加入 android:visibility="gone"

2.  packages\apps\Launcher2\res\layout-port\launcher.xml

1 <com.android.launcher2.DrawableStateProxyView 
2             android:id="@+id/voice_button_proxy" 
3             android:layout_width="80dp" 
4             android:layout_height="@dimen/qsb_bar_height" 
5             android:layout_gravity="top|right" 
6             android:clickable="false"    //modify this value to false 
7             onClick="onClickVoiceButton" 
8             android:importantForAccessibility="no" 
9             launcher:sourceViewId="@+id/voice_button" />
android:clickable属性修改为"false"

3.  Launcher2\src\com\android\launcher2\SearchDropTargetBar.java 中onFinishInflate() 方法内,将mQSBSearchBarAnim 相关的部分作如下修改

1     // Create the various fade animations
 2         if (mEnableDropDownDropTargets) {
 3             mDropTargetBar.setTranslationY(-mBarHeight);
 4             mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY",
 5                     -mBarHeight, 0f);
 6             mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY",  -mBarHeight ,
 7                     -mBarHeight); //modify 3rd para to -mBarHeight
 8         } else {
 9             mDropTargetBar.setAlpha(0f);
10             mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
11             mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha",  0f , 0f); //modify 3rd para to 0f;
12         }

4.  仍然是这只 java 文件,将showSearchBar 方法作如下修改:

1 public void showSearchBar(boolean animated) {
 2 
 3         if (!mIsSearchBarHidden) return;
 4         if (animated) {
 5             prepareStartAnimation(mQSBSearchBar);
 6             mQSBSearchBarAnim.reverse();
 7         } else {
 8             mQSBSearchBarAnim.cancel();
 9             if (mEnableDropDownDropTargets) {
10                 mQSBSearchBar.setTranslationY(0);
11             } else {
12                 mQSBSearchBar.setAlpha( 0f ); //参数改为 0f;
13             }
14         }
15         mIsSearchBarHidden = false;
16     }

 

三、hotseat的修改

改完之后,我们会发现hotseat排列到右边去了,显的很不美观是不是?作为车载导航的launcher,我们肯定是希望hotseat能排布在屏幕的Bottom啊,没关系,我们来改一下:

  首先,我们需要修改Hotseat.java

1 public Hotseat(Context context, AttributeSet attrs, int defStyle) {
 2   super(context, attrs, defStyle);
 3 
 4   TypedArray a = context.obtainStyledAttributes(attrs,
 5   R.styleable.Hotseat, defStyle, 0);
 6   mCellCountX = a.getInt(R.styleable.Hotseat_cellCountX, -1);
 7   mCellCountY = a.getInt(R.styleable.Hotseat_cellCountY, -1);
 8   mAllAppsButtonRank = context.getResources().getInteger(R.integer.hotseat_all_apps_index);
 9   mIsLandscape = false;//context.getResources().getConfiguration().orientation ==
10   //Configuration.ORIENTATION_LANDSCAPE;
11 }

    注意这里有一个大屏幕还是小屏幕的判断,这个是用来判断属于平板系统还是一般的手机系统。因为我系统是只会在横屏时使用,所以我直接设置成mIsLandscape为小屏幕,因为Hotseat里面很多获取熟悉都是区分大小屏幕。小屏幕的时候,我们使用竖向配置hotseat就可以得到相当于手机系统的hotseat效果,hotseat会显示在屏幕底下。

    下面我们看看Hotseat的配置文件,Hotseat是属于workspace的,所以需要在workspace配置文件里面配置,打开launcher.xml就可以看到hotseat的配置,这个并不是所有launcher.xml文件都有hotseat属性,如果你的launcher要适配多个分辨率的机器,那么你就得在适合你机器的分辨率下的相应的目录下的launcher.xml下添加hotseat属性。这里需要将android:layout_height和android:layout_width的属性对调一下,然后将android:layout_gravity改为bottom

1 <include layout="@layout/hotseat"
2 android:id="@+id/hotseat"
3 android:layout_height="@dimen/button_bar_height_plus_padding"
4 android:layout_width="match_parent"
5 android:layout_gravity="bottom" />

改完这个还是不够的,运行的时候,你会发现hotseat图标都缩到一起去了,还有一个地方也需要修改,layout-land/hotseat.xml也是需要做一下配置改动的

1 <com.launcherjellybean.android.Hotseat
 2 xmlns:android="http://schemas.android.com/apk/res/android"
 3 xmlns:launcher="http://schemas.android.com/apk/res/com.launcherjellybean.android"
 4 launcher:cellCountX="@integer/hotseat_cell_count"
 5 launcher:cellCountY="1">
 6 <com.launcherjellybean.android.CellLayout
 7 android:id="@+id/layout"
 8 android:layout_width="wrap_content"
 9 android:layout_height="match_parent"
10 android:layout_gravity="center"
11 android:paddingTop="@dimen/button_bar_height_top_padding"
12 android:paddingBottom="@dimen/button_bar_height_bottom_padding"
13 android:paddingLeft="@dimen/button_bar_width_left_padding"
14 android:paddingRight="@dimen/button_bar_width_right_padding"
15 
16 launcher:cellWidth="@dimen/hotseat_cell_width"
17 launcher:cellHeight="@dimen/hotseat_cell_height"
18 launcher:widthGap="@dimen/hotseat_width_gap"
19 launcher:heightGap="@dimen/hotseat_height_gap"
20 launcher:maxGap="@dimen/workspace_max_gap" />
21 </com.launcherjellybean.android.Hotseat>

其中launcher:cellCountX的值和launcher:cellCountY是需要对调的,你想想就知道为什么了

另外android:layout_height也需要从wrap_content变成match_parent,去查查他们的区别,你就知道为什么这么改了

 

光是这么改,也依然不够,原生桌面图标是4* 4的布局,如果把hotseat挪下来,就变成了5 *4的图标了,显然,太拥挤了,那么就需要修改桌面的行列数,打开文件values/config.xml,修改以下2个字段

<integer name="cell_count_x">4</integer>
<integer name="cell_count_y">3</integer>

这里我将cell_count_y从4改成了3,从而让hotseat占据了第四行,运行发现除了hotseat那一行的图标,其余图标都排布的比较下面,这是什么原因呢,这是因为桌面图标的高度是自适应居中的,由于我们修改了配置为3行,那么桌面图标自然在上下都留出了相应的高度,以便让图标居中了,所以,我们要让桌面图标知道,最后一行是被hotseat给占据了,从而还需要修改launcher.xml这个文件

1 <com.launcherjellybean.android.Workspace
 2 android:id="@+id/workspace"
 3 android:layout_width="match_parent"
 4 android:layout_height="match_parent"
 5 android:paddingLeft="@dimen/workspace_left_padding"
 6 android:paddingRight="@dimen/workspace_right_padding"
 7 android:paddingTop="0dp"
 8 android:paddingBottom="60dp"
 9 launcher:defaultScreen="1"
10 launcher:cellCountX="@integer/cell_count_x"
11 launcher:cellCountY="@integer/cell_count_y"
12 launcher:pageSpacing="@dimen/workspace_page_spacing"
13 launcher:scrollIndicatorPaddingLeft="@dimen/qsb_bar_height"
14 launcher:scrollIndicatorPaddingRight="@dimen/button_bar_height">

这里,我修改了android:paddingBottom 和 android:paddingTop这2个值,以让图标看起来不会那么奇怪,这样,已经成功了一大半了

 

四、去掉多余的2根竖线

我们修改完以上的东西,会发现还多了2根竖线,一根是google search bar留下的,另外一根是hotseat剩下的,放在2边很不美观,对吧,绝壁要去掉啊!!! 那么,这2根讨厌的竖线在哪呢,它们就藏在launcher.java里:

1 private View mQsbDivider;
2 private View mDockDivider;

我们找到和这2个变量有关的代码,全部予以屏蔽即可,比如hideDockDivider() 、showDockDivider()这些之类的,要坚决予以屏蔽,另外在WorkSpace.java里也发现了它们的身影:

1 void setFadeForOverScroll(float fade) {
 2 if (!isScrollingIndicatorEnabled()) return;
 3 
 4 mOverscrollFade = fade;
 5 float reducedFade = 0.5f + 0.5f * (1 - fade);
 6 final ViewGroup parent = (ViewGroup) getParent();
 7 // final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider));
 8 // final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider));
 9 final View scrollIndicator = getScrollingIndicator();
10 
11 cancelScrollingIndicatorAnimations();
12 //if (qsbDivider != null) qsbDivider.setAlpha(reducedFade);
13 //if (dockDivider != null) dockDivider.setAlpha(reducedFade);
14 scrollIndicator.setAlpha(1 - fade);
15 }

也跟我一起屏蔽它们就可以了,这样烦人的竖线就不会出现了,你也会做到和我在一开始展示的那样的效果。

 

Ps:最近有有收到站内信息,说要加我QQ,说想交流下,那这样吧

 

(the End)