很久没写Launcher分析的文章,最近实在太忙。今天七夕本来是想陪女朋友逛街 ,碰巧打台风呆在家里,就继续写一篇文章。今天主要是讲一下Launcher里面的Widget列表,这方面信息比较多,今天重点讲一下Widget信息收集和Launcher是如何显示Widget。这是这个系列第12篇文章,可是有关Launcher的分析感觉还有很多东西要写。

  Widget列表是Android4.0以后才有的一种新特性,主要是可以直接查看Widget的缩略图,方便用户使用。而且Widget列表放到了AllApp里面,用一个TabHost管理。有关AllApp的TabHost切换,可以参考我前面的文章:AllApp全部应用列表(AppsCustomizeTabHost) 。Widget列表就是在AllApp列表后面。下面是Launcher4.0 的Widget列表:

(PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)

1、AppsCustomizePagedView关系

  首先看看Launcher是如何获取系统里面所有的Widget信息,这一部分都在AppsCustomizePagedView类里面,AppsCustomizePagedView类是同时管理显示Widget和所有应用列表。这两者都是这个类负责显示,看名字我们可以看到一个很熟悉的名字PagedView类,这个类前面我已经分析过,是一个十分重要的积累,继承于ViewGroup。主界面的WorkSpace也是继承于PagedView,PagedView主要是实现了页面滑动功能。AppsCustomizePagedView的基类同样是PagedView,下面看看他们的继承关系:

  从上面的继承关系可以看到,AppsCustomizePagedView也是一个GroupView,主要就是用来显示其他view,只是多了页面滑动和拖曳功能。其实这个继承关系跟WorkSpace是基本一样,只是中间的类有点不一样。不了解的朋友,可以看我以前WorkSpace的分析文章。

2、Widgets信息收集

下面我们看看AppsCustomizePagedView里面如何统计系统里面Widget的信息。所有的Widget信息会最后保存到一个队列里面:


//Edited by mythou
//http://www.cnblogs.com/mythou/
private ArrayList<Object> mWidgets;  //widget资源

下面我们看看,如何统计收集信息

//Edited by mythou
//http://www.cnblogs.com/mythou/
  public void updatePackages() {
//清空WIdget列表
boolean wasEmpty = mWidgets.isEmpty();
mWidgets.clear();
     //这里获取的是Widget信息
List<AppWidgetProviderInfo> widgets = AppWidgetManager.getInstance(
mLauncher).getInstalledProviders();
Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
    //获取所有的快捷方式,需要说明的是快捷方式同样显示在Widget里面
List<ResolveInfo> shortcuts = mPackageManager.queryIntentActivities(
shortcutsIntent, );
     //遍历所有的Widget插件
for (AppWidgetProviderInfo widget : widgets) {
        //判断插件的最小高宽是否为0,为0不需要显示
if (widget.minWidth > && widget.minHeight > ) {
          //添加到队列
mWidgets.add(widget);
} else {
Log.e(LOG_TAG, "Widget " + widget.provider
+ " has invalid dimensions (" + widget.minWidth + ", "
+ widget.minHeight + ")");
}
}
     //直接添加所有快捷方式
mWidgets.addAll(shortcuts);
Collections.sort(mWidgets,
new LauncherModel.WidgetAndShortcutNameComparator(
mPackageManager));
updatePageCounts(); if (wasEmpty) {
// The next layout pass will trigger data-ready if both widgets and
// apps are set, so request
// a layout to do this test and invalidate the page data when ready.
if (testDataReady())
requestLayout();
} else {
cancelAllTasks();
invalidatePageData();
}
}

  上面就是如何获取系统Widget信息的相关代码,主要是通过AppWidgetManager服务获取相关信息。需要注意的是,快捷方式也会显示在Widget列表里面,获取快捷方式的方法,主要是通过Intent的标记识别。通过PackageManager.queryIntentActivities,可以指定过滤所有含有ACTION_CREATE_SHORTCUT标识的程序,这些作为快捷方式也会被添加到Widget队列里面。

3、Widget信息初始化

  上面说的是如何获取Widget的相关对象信息,我们可以看到ArrayList里面的类型也是初始化为Object。下面我们看看如何提取Widget里面的信息,然后初始化为View在界面上面显示。

//Edited by mythou
//http://www.cnblogs.com/mythou/
 public void syncWidgetPageItems(final int page, final boolean immediate) {
int numItemsPerPage = mWidgetCountX * mWidgetCountY; //计算Widget相关的长宽和边距,用于后面确定位置
final ArrayList<Object> items = new ArrayList<Object>();
int contentWidth = mWidgetSpacingLayout.getContentWidth();
final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft
- mPageLayoutPaddingRight - ((mWidgetCountX - ) * mWidgetWidthGap)) / mWidgetCountX);
int contentHeight = mWidgetSpacingLayout.getContentHeight();
final int cellHeight = ((contentHeight - mPageLayoutPaddingTop
- mPageLayoutPaddingBottom - ((mWidgetCountY - ) * mWidgetHeightGap)) / mWidgetCountY); // 这里是计算Widget的数目和每页数目,用于后面计算WIdget的预览图
int offset = page * numItemsPerPage;
for (int i = offset; i < Math.min(offset + numItemsPerPage,
mWidgets.size()); ++i) {
items.add(mWidgets.get(i));
} //获取Widget信息,填充到PagedViewWidget对象里面
final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page
+ mNumAppsPages);
layout.setColumnCount(layout.getCellCountX());
     //遍历所有widget和快捷方式
for (int i = ; i < items.size(); ++i) {
Object rawInfo = items.get(i);
PendingAddItemInfo createItemInfo = null;
PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
R.layout.apps_customize_widget, layout, false);
        //Widget信息
if (rawInfo instanceof AppWidgetProviderInfo) {
// Fill in the widget information
AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
createItemInfo = new PendingAddWidgetInfo(info, null, null);
int[] cellSpans = mLauncher.getSpanForWidget(info, null);
widget.applyFromAppWidgetProviderInfo(info, -, cellSpans,
mHolographicOutlineHelper);
widget.setTag(createItemInfo);
}
        //快捷方式
        else if (rawInfo instanceof ResolveInfo) {
// Fill in the shortcuts information
ResolveInfo info = (ResolveInfo) rawInfo;
createItemInfo = new PendingAddItemInfo();
createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
createItemInfo.componentName = new ComponentName(
info.activityInfo.packageName, info.activityInfo.name);
widget.applyFromResolveInfo(mPackageManager, info,
mHolographicOutlineHelper);
widget.setTag(createItemInfo);
}
widget.setOnClickListener(this);
widget.setOnLongClickListener(this);
widget.setOnTouchListener(this);
widget.setOnKeyListener(this); //计算每个Widget的位置和布局信息
int ix = i % mWidgetCountX;
int iy = i / mWidgetCountX;
GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
GridLayout.spec(iy, GridLayout.LEFT), GridLayout.spec(ix,
GridLayout.TOP));
lp.width = cellWidth;
lp.height = cellHeight;
lp.setGravity(Gravity.TOP | Gravity.LEFT);
if (ix > )
lp.leftMargin = mWidgetWidthGap;
if (iy > )
lp.topMargin = mWidgetHeightGap;
layout.addView(widget, lp);
}

  上面是从我们获取的Widget对象里面提取Widget信息,包括位置,最小长宽和预览图。这里分开了Widget和快捷方式,这两种处理稍有不同,可以根据上面代码对比。下面以Widget为例,说说如何生成界面显示的效果。

4、Widget预览图

  其实界面上我们看到的Widget预览图也是一个布局生成的,就是一个LinearLayout,下面我们简单看看布局文件R.layout.apps_customize_widget:

//Edited by mythou
//http://www.cnblogs.com/mythou/
<com.android.launcher2.PagedViewWidget
android:background="@drawable/focusable_view_bg"
android:focusable="true"> <LinearLayout
android:orientation="horizontal">
<!--Widget名称和占用空间-->
<TextView
android:textSize="20sp" /> <TextView
android:textSize="30sp" />
</LinearLayout>

<!-- Widget的预览图-->

<com.android.launcher2.PagedViewWidgetImageView
android:id="@+id/widget_preview"
android:scaleType="matrix" /> </com.android.launcher2.PagedViewWidget>

  上面是Widget预览图的布局(我这里删除了很多属性,只是给个布局示意),主要就是用了两个TextView和一个ImageView实现,预览图的ImageView被重载了,实现了其他功能。根部局的LinearLayout也被重载,加入其他功能。这里不针对这两个类详细分析,PagedViewWidget里面实现了较多功能,包括主要的重绘功能。PagedViewWidgetImageView基本没有做什么事,可以直接当做ImageView使用。

  上面的信息初始化过程,就是加载了这个布局,然后生成对应的对象,然后设置各种信息以及动作监听器。

//Edited by mythou
//http://www.cnblogs.com/mythou/
PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
R.layout.apps_customize_widget, layout, false);

5、结语

  从收集系统信息到初始化相关信息到生成对象大概就是这个过程。Widget缩略图生成过程比较复杂,这个下次再说吧,今天大伙早点休息,七夕快乐!

2013-8-13

Edited by 泡泡糖

系列文章:

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

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

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

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

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

Android Launcher分析和修改6——页面滑动(PagedView

Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)

Android Launcher分析和修改8——AllAPP界面拖拽元素(PagedViewWithDraggableItems)

Android Launcher分析和修改9——Launcher启动APP流程

Android Launcher分析和修改10——HotSeat深入进阶

Android Launcher分析和修改11——自定义分页指示器(paged_view_indicator)

Edited by mythou

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

Android Launcher分析和修改12——Widget列表信息收集的更多相关文章

  1. Android Launcher分析和修改13——实现Launcher编辑模式(1) 壁纸更换

    已经很久没更新Launcher系列文章,今天不分析源码,讲讲如何在Launcher里面添加桌面设置的功能.目前很多第三方Launcher或者定制Rom都有简单易用的桌面设置功能.例如小米MIUI的La ...

  2. Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)

    今天主要是分析一下Launcher里面的所有应用列表.Android4.0 Launcher的所有应用列表跟2.X比较大的区别就是多了Widget的显示.下面会详细分析Launcher里面有关所有应用 ...

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

    上面一篇文章说了Launcher是如何被启动的,Launcher启动的过程主要是加载界面数据然后显示出来, 界面数据都是系统APP有关的数据,都是从Launcher的数据库读取,下面我们详细分析Lau ...

  4. Android Launcher分析和修改9——Launcher启动APP流程

    本来想分析AppsCustomizePagedView类,不过今天突然接到一个临时任务.客户反馈说机器界面的图标很难点击启动程序,经常点击了没有反应,Boss说要优先解决这问题.没办法,只能看看是怎么 ...

  5. Android Launcher分析和修改10——HotSeat深入进阶

    前面已经写过Hotseat分析的文章,主要是讲解如何在Launcher里面配置以及修改Hotseat的参数.今天主要是讲解一下如何在Hotseat里面的Item显示名称.这个小问题昨天折腾了半天,最后 ...

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

    前面两篇文章都是写有关Launcher配置文件的修改,代码方面涉及不多,今天开始进入Launcher代码分析. 我们开机启动Launcher,Launcher是由Activity Manager启动的 ...

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

    今天主要是分析一下Launcher里面的快捷方式导航条——HotSeat,一般我们使用手机底下都会有这个导航条,但是如果4.0的Launcher放到平板电脑里面运行,默认是没有HotSeat的,刚好我 ...

  8. Android Launcher分析和修改8——AllAPP界面拖拽元素(PagedViewWithDraggableItems)

    接着上一篇文章,继续分析AllAPP列表界面.上一篇文章分析了所有应用列表的界面构成以及如何通过配置文件修改属性.今天主要是分析PagedViewWithDraggableItems类,因为在我们分析 ...

  9. Android Launcher分析和修改11——自定义分页指示器(paged_view_indicator)

    Android4.0的Launcher自带了一个简单的分页指示器,就是Hotseat上面那个线段,这个本质上是一个ImageView利用.9.png图片做,效果实在是不太美观,用测试人员的话,太丑了. ...

随机推荐

  1. SpringBoot+Mybatis多模块(module)项目搭建教程

    一.前言 最近公司项目准备开始重构,框架选定为SpringBoot+Mybatis,本篇主要记录了在IDEA中搭建SpringBoot多模块项目的过程. 1.开发工具及系统环境 IDE:Intelli ...

  2. ACM差分约束笔记

    https://www.cnblogs.com/31415926535x/p/10463112.html 很早之前学最短路的时候就看了一眼差分约束,,当时以为这种问题不怎么会出现,,而且当时为了只为了 ...

  3. Java并发程序设计(三) Java内存模型和线程安全

    Java内存模型和线程安全 一 .原子性 原子性是指一个操作是不可中断的.即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰. 思考:i++是原子操作吗?  二.有序性 Java代 ...

  4. c潭州课堂25班:Ph201805201 MySQL第二课 (课堂笔记)

    mysql> create table tb_2( -> id int, -> name varchar(10) not null -> ); 插入数据 insert into ...

  5. C语言字符串操作详细总结

    1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度 ...

  6. 把Catalina的字符串格式转化为日期格式

    public static void distinctCoords(LinkedList list,String date,String imei,double GpsLat,double GpsLn ...

  7. 以添加评论组件为例看angular2请求数据的处理

    在NiceFish项目中,数据请求处理并没有用Promise的那一套方法,用的是Observable(观察者模式),我将其理解成生产者和消费者模式 如下简单例子:出自(https://segmentf ...

  8. linux tail命令的使用方法详解

    本文介绍Linux下tail命令的使用方法. linux tail命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来,就是把某个档案文件的最后几行显示到终端上,假设该档案有更 ...

  9. Mongoose多数据库连接及实用样例

    使用环境: MongoDB 3.6 插件版本: "mongodb": "^3.1.10","mongoose": "^5.4.2& ...

  10. 如何正确地使用android中的progressdialog

    网上有很多关于progressdialog的用法的介绍,下面这个是最具代表性的: http://sd8089730.iteye.com/blog/1441610 其核心代码: Handler hand ...