博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Android Launcher分析和修改5——HotSeat分析

Posted on 2013-07-04 21:14  泡泡糖  阅读(12295)  评论(1编辑  收藏  举报

  今天主要是分析一下Launcher里面的快捷方式导航条——HotSeat,一般我们使用手机底下都会有这个导航条,但是如果4.0的Launcher放到平板电脑里面运行,默认是没有HotSeat的,刚好我这里的运行环境类似平板,系统默认把HotSeat去掉了。办法,只能自己想办法把它弄出来,所以今天主要是分析如何在你Launcher上添加HotSeat以及分析HotSeat实现。

  Hotseat配置是通过配置文件控制的,一般来说,你需不需要Hotseat只要在配件文件里面写一下就OK,不过Hotseat有一个比较麻烦的地方,就是需要注意横屏还是竖屏。默认竖屏的时候,Hotseat是屏幕底下的,横屏的时候,在屏幕右边。不知道google当时为啥要这样设计,可能是为了横屏的时候,不占用本来就不多的竖向的空间吧。不过这个设计对于一些横屏的平板电脑或者移动设备,用户体验实在不太好。

 

1、Hotseat配置文件

  下面我们看看Hotseat的配置文件,Hotseat是属于workspace的,所以需要在workspace配置文件里面配置,打开launcher.xml就可以看到hotseat的配置,这个并不是所有launcher.xml文件都有hotseat属性。例如:layout-sw600dp件夹下的launcher.xml就是默认没有hotseat配置,这个使用在大屏幕,平板之类的设置上。而我的设备刚好是使用这个配置。

所以把hotseat加到layout-sw600dp下的launcher.xml配置文件:


//Edited by mythou
//http://www.cnblogs.com/mythou/
    <!-- WorkSpace最下面的五个快捷位置  mythou-->
    <include layout="@layout/hotseat"
        android:id="@+id/hotseat"
        android:layout_width="match_parent"
        android:layout_height="@dimen/button_bar_height_plus_padding"
        android:layout_gravity="bottom" />

  注意,我这里是使用了竖屏时的hotseat配置,因为我希望hotseat是放到屏幕下方。所以android:layout_gravity=

"bottom"也是配置为bottom。hotseat默认是有5个按钮,其中中间一个是进入AllApp列表的按钮,这个是程序里面设置

(下面会说到)。其他的默认按钮需要在default_workspace.xml里面配置。

 


//Edited by mythou
//http://www.cnblogs.com/mythou/
  <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
  <!-- 使用screen作为按钮位置标识-->
<favorite launcher:packageName="com.example.naviback" launcher:className="com.example.naviback.MainActivity" launcher:container="-101" launcher:screen="0" launcher:x="0" launcher:y="0" /> <favorite launcher:packageName="com.csr.dvd" launcher:className="com.csr.dvd.LoadDVD" launcher:container="-101" launcher:screen="1" launcher:x="1" launcher:y="0" /> <favorite launcher:packageName="com.apical.apicalradio" launcher:className="com.apical.apicalradio.RadioMainActivity" launcher:container="-101" launcher:screen="3" launcher:x="3" launcher:y="0" /> <favorite launcher:packageName="com.csr.BTApp" launcher:className="com.csr.BTApp.CSRBluetoothDemoActivity" launcher:container="-101" launcher:screen="4" launcher:x="4" launcher:y="0" />

 

default_workspace的配置,我在第一篇文章里面已经说过了,不清楚的可以点击这里 。配置hotseat的属性跟workspace的有点不一样,下面针对不同的属性进行说明:

  • launcher:container:需要标识为-101 ,代表是hotseat的默认按钮。
  • launcher:screen:代表按钮的位置,0是第一个位置。ALlApp按钮默认是2,所以上面并没有screen为2的标签。
其他的属性跟workspace配置的属性一样,可以参考我写的第一篇文章。

配置完hotseat的默认按钮后,我们需要修改hotseat.xml的配置属性才能正常显示,下面是hotseat.xml的配置,

我是使用了竖屏时的hotseat配置。

//Edited by mythou
//http://www.cnblogs.com/mythou/
<com.android.launcher2.Hotseat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
    android:background="@drawable/hotseat_bg_panel"  <!--设置hotseat的背景 --> 
    launcher:cellCountX="5"   <!-- 代表hotseat横向有多少个方格(图标) -->
    launcher:cellCountY="1">  <!-- 代码hotseat竖向有多少个方格-->
    <com.android.launcher2.CellLayout     <!--实际容纳按钮的容器是CellLayout -->
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
     <!--下面几个属性就是控制5个按钮的显示位置调整,跟我们一般使用控件属性一样 --> android:paddingTop="3dp" android:paddingBottom="3dp" android:paddingLeft="150dp" android:paddingRight="@dimen/button_bar_height_bottom_padding"      <!-- hotseat里面按钮的大小以及两个按钮之间的间距 --> launcher:cellWidth="106dip" launcher:cellHeight="106dip" launcher:widthGap="25dp" launcher:heightGap="@dimen/hotseat_height_gap" launcher:maxGap="@dimen/workspace_max_gap" /> </com.android.launcher2.Hotseat>

 

  上面的属性,有几个我们是需要留意,因为这是直接关系我们hotseat的显示效果。上面我已经给出了一些关键属性大部分跟我们使用一般控件是一样的,其他的launcher:XXX就是launcher自己定义的属性。上面已经给出注释。需要注意的是launcher:cellCountX和launcher:cellCountY两个属性,这个跟横向竖向的hotseat有关。另外就是从中我们也可以看到其实hotseat可以定义多行多列。因为hotseat里面其实是包含了一个CellLayout,跟workspace一样。

  除了设置Hotseat的属性外,我们还需要设置workspace的属性,以为hotseat占用了一部分的空间,所以workspace就需要腾出一部分空间处理。例如原来你的workspace没有加入hotseat前是5*3设置,如果需要加入hotseat,你的workspace只能修改为5*2的配置,你需要在竖向空间流出一行的空间给hotseat使用。

 

2、Hotseat构造函数

到这里基本上配置已经设置好。不过显示出来的效果并不是我们想象的结果,因为Hotseat内部对横向和竖向屏幕做了处理,我们需要做些修改。Launcher里面有专门管理Hotseat的类:Hotseat.java 。

下面我们看看Hotseat.java的构造:

//Edited by mythou
//http://www.cnblogs.com/mythou/
    public Hotseat(Context context, AttributeSet attrs, int defStyle) 
  { super(context, attrs, defStyle); TypedArray a
= context.obtainStyledAttributes(attrs, R.styleable.Hotseat, defStyle, 0); mCellCountX = a.getInt(R.styleable.Hotseat_cellCountX, -1); mCellCountY = a.getInt(R.styleable.Hotseat_cellCountY, -1); mIsLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; //设置成竖屏,使用竖屏时候的hotseat mIsLandscape = false; }

注意这里有一个大屏幕还是小屏幕的判断,这个是用来判断属于平板系统还是一般的手机系统。因为我系统是只会在横屏时使用,

所以我直接设置成mIsLandscape为小屏幕,因为Hotseat里面很多获取熟悉都是区分大小屏幕。小屏幕的时候,我们使用竖向

配置hotseat就可以得到相当于手机系统的hotseat效果,hotseat会显示在屏幕底下。

基本上修改上面几个地方,就可以在平板屏幕底下显示hotseat。下面我们分析一下Hotseat是如何实现的。

 

3、Hotseat加载数据

Hotseat加载数据可以分为两部分,AllApp按钮和其他默认按钮。下面我们先看看其他默认按钮是如何加载的:

默认按钮加载跟workspace的默认数据加载一样,都是在LauncherModel加载。

Hotseat和workspace的app类型加载方式一样,


//Edited by mythou
//http://www.cnblogs.com/mythou/
private void loadWorkspace() 
{
  //........
switch (container) { case LauncherSettings.Favorites.CONTAINER_DESKTOP: case LauncherSettings.Favorites.CONTAINER_HOTSEAT: sWorkspaceItems.add(info); break; //........ }

上面是上一篇我们分析Launcher加载初始化数据的部分代码,我们可以看到,Hotseat的数据加载跟workspace的一般APP快捷方式加载是一样的,而且他们共用一个队列保存数据。具体数据加载过程分析可以查看我上一篇文章。

 

4、Hotseat绑定数据

 hotseat绑定数据跟workspace流程基本一样,下面是hotseat开始绑定时,调用了Hotseat自身的方法清空数据。

public void startBinding() 
{  
   //..........
   // 清空Hotseat的数据
    if (mHotseat != null) 
  { mHotseat.resetLayout(); } }

上面配置文件分析的时候,我们也说了Hotseat里面其实也是一个CellLayout负责管理内部的元素,下面我们看看它如何绑定数据

到CellLayout。在workspace.java类里面的addInScreen()方法实现。

//Edited by mythou
//http://www.cnblogs.com/mythou/
 void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,
            boolean insert) {
    //...........

    //创建CellLayout,用于添加Hotseat的对象。 final CellLayout layout;
if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { layout = mLauncher.getHotseat().getLayout(); child.setOnKeyListener(null); // Hide folder title in the hotseat if (child instanceof FolderIcon) { ((FolderIcon) child).setTextVisible(false); } if (screen < 0) { screen = mLauncher.getHotseat().getOrderInHotseat(x, y); } else { // Note: We do this to ensure that the hotseat is always laid out in the orientation // of the hotseat in order regardless of which orientation they were added //获取child的位置,返回true添加成功,false失败 x = mLauncher.getHotseat().getCellXFromOrder(screen); y = mLauncher.getHotseat().getCellYFromOrder(screen); } } else { //如果Hotseat里面有Folder,隐藏文件夹名字 if (child instanceof FolderIcon) { ((FolderIcon) child).setTextVisible(true); } layout = (CellLayout) getChildAt(screen); child.setOnKeyListener(new IconKeyEventListener()); }   //......... }

这里只给出Hotseat关键的添加代码,其他一些相关的内容,可以查看源码。

 

5、Hotseat类

Hotseat类里面其实东西不多,主要就是我们上面说的构造函数,另外还有下面的设置AllAPP按钮的方法。

//Edited by mythou
//http://www.cnblogs.com/mythou/
void resetLayout() {
    //清空原来的内容 mContent.removeAllViewsInLayout();
//添加AllAPP按钮,也是一个BubbleTextView对象 Context context = getContext(); LayoutInflater inflater = LayoutInflater.from(context); BubbleTextView allAppsButton = (BubbleTextView) inflater.inflate(R.layout.application, mContent, false);
     //加载AllAPP按钮的图标,这里使用了selector作为按钮配置 allAppsButton.setCompoundDrawablesWithIntrinsicBounds(
null, context.getResources().getDrawable(R.drawable.all_apps_button_icon), null, null); // allAppsButton.setText(context.getString(R.string.all_apps_button_label)); allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label)); //allapp按钮触摸和点击响应,回调Launcher的功能 allAppsButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (mLauncher != null && (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) { mLauncher.onTouchDownAllAppsButton(v); } return false; } });      //AllAPP按钮点击响应的方法,点击的处理在Launcher类里面 allAppsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(android.view.View v) { if (mLauncher != null) { mLauncher.onClickAllAppsButton(v); } } });      //这里会判断是小屏幕还是大屏幕,决定AllAPP按钮的位置 int x = getCellXFromOrder(sAllAppsButtonRank); int y = getCellYFromOrder(sAllAppsButtonRank); Log.d("Mythou_Launcher", "Hotseat------>x="+x+" y="+y); //Hotseat中清空了装载的内容,然后重新加载allAppsButton到CellLayout mythou mContent.addViewToCellLayout(allAppsButton, -1, 0, new CellLayout.LayoutParams(x,y,1,1), true); }

Hotseat里面其他几个简单方法,基本上都是获取一些属性,这里就不详细分析。

6、总结

  • Hotseat其实也是一个CellLayout负责管理里面的所有数据。
  • 大部分配置可以通过XML配置文件修改得到。
  • 加载和绑定数据和workspace基本是一致的。

今天就写到这里,有关CellLayout的分析,下一篇文章会讲述。

 

系列文章:

Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)

Android Launcher分析和修改2——Icon修改、界面布局调整、壁纸设置

Android Launcher分析和修改3——Launcher启动和初始化

Android Launcher分析和修改4——初始化加载数据

 

Edited by mythou

原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3172409.html