• Android Launcher分析和修改12——Widget列表信息收集


      很久没写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, 0);
         //遍历所有的Widget插件
    for (AppWidgetProviderInfo widget : widgets) {
            //判断插件的最小高宽是否为0,为0不需要显示
    if (widget.minWidth > 0 && widget.minHeight > 0) {
              //添加到队列 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 - 1) * mWidgetWidthGap)) / mWidgetCountX);
            int contentHeight = mWidgetSpacingLayout.getContentHeight();
            final int cellHeight = ((contentHeight - mPageLayoutPaddingTop
                    - mPageLayoutPaddingBottom - ((mWidgetCountY - 1) * 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 = 0; 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, -1, 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 > 0) lp.leftMargin = mWidgetWidthGap; if (iy > 0) 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 

  • 相关阅读:
    adb devices检测不到夜神模拟器
    adb devices检测不到夜神模拟器
    adb devices检测不到夜神模拟器
    epoll里面mmap释疑
    epoll里面mmap释疑
    epoll里面mmap释疑
    epoll里面mmap释疑
    Redis数据迁移的三个方法
    Redis数据迁移的三个方法
    MySQL:由USE DB堵塞故障引发的思考
  • 原文地址:https://www.cnblogs.com/mythou/p/3256212.html
Copyright © 2020-2023  润新知