Android Launcher分析和修改5——HotSeat分析
今天主要是分析一下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=""
launcher:x=""
launcher:y="" />
<favorite
launcher:packageName="com.csr.dvd"
launcher:className="com.csr.dvd.LoadDVD"
launcher:container="-101"
launcher:screen=""
launcher:x=""
launcher:y="" />
<favorite
launcher:packageName="com.apical.apicalradio"
launcher:className="com.apical.apicalradio.RadioMainActivity"
launcher:container="-101"
launcher:screen=""
launcher:x=""
launcher:y="" />
<favorite
launcher:packageName="com.csr.BTApp"
launcher:className="com.csr.BTApp.CSRBluetoothDemoActivity"
launcher:container="-101"
launcher:screen=""
launcher:x=""
launcher:y="" />
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="" <!-- 代表hotseat横向有多少个方格(图标) -->
launcher:cellCountY=""> <!-- 代码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, );
mCellCountX = a.getInt(R.styleable.Hotseat_cellCountX, -);
mCellCountY = a.getInt(R.styleable.Hotseat_cellCountY, -);
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 < ) {
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, -, , new CellLayout.LayoutParams(x,y,,),
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
Android Launcher分析和修改5——HotSeat分析的更多相关文章
- Android Launcher分析和修改10——HotSeat深入进阶
前面已经写过Hotseat分析的文章,主要是讲解如何在Launcher里面配置以及修改Hotseat的参数.今天主要是讲解一下如何在Hotseat里面的Item显示名称.这个小问题昨天折腾了半天,最后 ...
- Android Launcher分析和修改13——实现Launcher编辑模式(1) 壁纸更换
已经很久没更新Launcher系列文章,今天不分析源码,讲讲如何在Launcher里面添加桌面设置的功能.目前很多第三方Launcher或者定制Rom都有简单易用的桌面设置功能.例如小米MIUI的La ...
- Android Launcher分析和修改9——Launcher启动APP流程
本来想分析AppsCustomizePagedView类,不过今天突然接到一个临时任务.客户反馈说机器界面的图标很难点击启动程序,经常点击了没有反应,Boss说要优先解决这问题.没办法,只能看看是怎么 ...
- Android Launcher分析和修改6——页面滑动(PagedView)
本来打算分析CellLayout的源码,不过因为它们之间是容器包含关系,所以打算先把PagedView分析.PagedView代码很多,今天主要是分析跟核心功能相关的代码.PagedView主要实现一 ...
- Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)
今天主要是分析一下Launcher里面的所有应用列表.Android4.0 Launcher的所有应用列表跟2.X比较大的区别就是多了Widget的显示.下面会详细分析Launcher里面有关所有应用 ...
- Android Launcher分析和修改8——AllAPP界面拖拽元素(PagedViewWithDraggableItems)
接着上一篇文章,继续分析AllAPP列表界面.上一篇文章分析了所有应用列表的界面构成以及如何通过配置文件修改属性.今天主要是分析PagedViewWithDraggableItems类,因为在我们分析 ...
- Android Launcher分析和修改11——自定义分页指示器(paged_view_indicator)
Android4.0的Launcher自带了一个简单的分页指示器,就是Hotseat上面那个线段,这个本质上是一个ImageView利用.9.png图片做,效果实在是不太美观,用测试人员的话,太丑了. ...
- Android Launcher分析和修改12——Widget列表信息收集
很久没写Launcher分析的文章,最近实在太忙.今天七夕本来是想陪女朋友逛街 ,碰巧打台风呆在家里,就继续写一篇文章.今天主要是讲一下Launcher里面的Widget列表,这方面信息比较多,今天重 ...
- Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)
最近工作都在修改Launcher,所以打算把分析源码和修改源码的过程记录下来,最近会写一些关于Launcher的分析和修改博文.因为我是修改4.0.3的Launcher,所以后面文章里面的Launch ...
随机推荐
- 002.Docker安装部署
一 docker安装-CentOS系统 1.1 docker自动安装脚本 root@docker:~# wget -qO- https://get.docker.com/ | sh 或—— root@ ...
- 机器学习 支持向量机(SVM) 从理论到放弃,从代码到理解
基本概念 支持向量机(support vector machines,SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器.支持向量机还包括核技巧,这使它成为实质上的非线性分 ...
- Flask使用SQLAlchemy两种方式
一.SQLAlchemy和Alembic 主要使用原生的SQLAlchemy进行数据库操作和使用Alemic进行数据库版本控制 I 创建数据库主要有三个步骤 创建表的父类/数据库连接/Session ...
- 安卓工作室 Android studio 或 Intellij IDEA 美化 修改 汉化 酷炫 装逼 Android studio or Intellij IDEA beautify modify Chinesization cool decoration
安卓工作室 Android studio 或 Intellij IDEA 美化 修改 汉化 酷炫 装逼 Android studio or Intellij IDEA beautify modify ...
- bzoj2830: [Shoi2012]随机树
题目链接 bzoj2830: [Shoi2012]随机树 题解 q1好做 设f[n]为扩展n次后的平均深度 那么\(f[n] = \frac{f[n - 1] * (n - 1) + f[n - 1] ...
- 洛谷.3355.骑士共存问题(最小割ISAP)
题目链接 一个很暴力的想法:每个点拆点,向不能同时存在的连边 但是这样边太多了,而且会有很多重复.我不会说我还写了还没过样例 我们实际就是在做一个最大匹配.考虑原图,同在黄/红格里的骑士是互不攻击的, ...
- [POI2014]Couriers
OJ题号:BZOJ3524.BZOJ2223.洛谷3567 思路: 维护一颗可持久化权值线段树,记录每次加入数字时,不同数字出现的个数.对于每一个询问$[l,r]$,同时查询以$r$和$l-1$为根的 ...
- c++模板 与 泛型编程基础
C++模板 泛型编程就是以独立于任何特定类型的方式编写代码,而模板是泛型编程的基础. (1)定义函数模板(function template) 函数模板是一个独立于类型的函数,可以产生函数的特定类型版 ...
- json数据格式 net.sf.json.JSONException: A JSONObject text must begin with '{' at character 1 of Error:(findColumns1)Read timed out
substring(3)的用法http://www.w3school.com.cn/jsref/jsref_substring.asp 可能一:sb是要转化的数据,以sb是String为例 ...
- 在AngularJS中实现一个延迟加载的Directive
所谓的延迟加载通常是:直到用户交互时才加载.如何实现延迟加载呢? 需要搞清楚三个方面: 1.html元素的哪个属性需要延迟加载?2.需要对数据源的哪个字段进行延迟加载?3.通过什么事件来触发延迟加载? ...