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 ...
随机推荐
- Linux上的压缩与归档
非常非常非常简要的描述而已. 压缩 压缩的简要原理是通过一些算法,拿CPU的计算时间去换磁盘上存储的空间.同时还可节省网络传输中的带宽. 对于文本文件的压缩效果比较好,对二进制程序.图片等文件的压缩效 ...
- php反序列化简叙
0x01 php简单的反序列化 这题是在网上看到的,原题连接不太了解,但是源码题目给了出来,稍微下文件名和排版在本地测试 <?php class SoFun{ protected $file=' ...
- 码云,git使用 教程-便签
码云,git使用 教程-便签 Code cloud, git use tutorial - note 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.c ...
- 2827: 千山鸟飞绝 非旋treap
国际惯例的题面:看起来很不可做的样子,我们先来整理一下题意吧.就是,维护每个点曾经拥有过的最大的两个属性值,支持把点的位置移动.我们用map对每个位置进行离散化,对每个位置建立一个平衡树.为了方便分离 ...
- POJ.1743.Musical Theme(后缀数组 倍增 二分 / 后缀自动机)
题目链接 \(Description\) 给定一段数字序列(Ai∈[1,88]),求最长的两个子序列满足: 1.长度至少为5 2.一个子序列可以通过全部加或减同一个数来变成另一个子序列 3.两个子序列 ...
- 洛谷.3807.[模板]卢卡斯定理(Lucas)
题目链接 Lucas定理 日常水题...sublime和C++字体死活不同步怎么办... //想错int范围了...不要被longlong坑 //这个范围现算阶乘比预处理快得多 #include &l ...
- 潭州课堂25班:Ph201805201 WEB 之 JS 第六课 (课堂笔记)
上节补充方法 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- c潭州课堂25班:Ph201805201 MySQL第二课 (课堂笔记)
mysql> create table tb_2( -> id int, -> name varchar(10) not null -> ); 插入数据 insert into ...
- Android MediaCodec的数据处理方式分析
*由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不 ...
- 各种组件的js 获取值 / js动态赋值
jQuery获取Select选择的Text和Value:语法解释:1. $("#select_id").change(function(){//code...}); //为Se ...