zoukankan      html  css  js  c++  java
  • Android Launcher 3 简单分析

    最近在学习Android Launcher的相关知识,在github上找到可以在Android studio上编译的Launcher 3代码,地址:https://github.com/rydanliu/Launcher3

    Launcher 3的界面主要由SearchDropTargetBar、Workspace、CellLayout、PageIndicator、Hotseat组成。如下图:

    Launcher 3 最主要的是一个Activity,基本上所有操作都集中在这个Activity上。这个Activity文件为Launcher.java,他的布局文件为launcher.xml。

    下面为竖屏的布局文件,路径为res/layout-port/launcher.xml。

     1 <?xml version="1.0" encoding="utf-8"?>
     2 
     3 <!-- Full screen view projects under the status bar and contains the background -->
     4 <com.android.launcher3.LauncherRootView xmlns:android="http://schemas.android.com/apk/res/android"
     5     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     6     android:id="@+id/launcher"
     7     android:layout_width="match_parent"
     8     android:layout_height="match_parent"
     9     android:fitsSystemWindows="true">
    10 
    11     <com.android.launcher3.DragLayer
    12         android:id="@+id/drag_layer"
    13 
    14         android:layout_width="match_parent"
    15         android:layout_height="match_parent">
    16 
    17         <com.android.launcher3.FocusIndicatorView
    18             android:id="@+id/focus_indicator"
    19             android:layout_width="22dp"
    20             android:layout_height="22dp" />
    21 
    22         <!-- The workspace contains 5 screens of cells -->
    23         <!-- DO NOT CHANGE THE ID -->
    24         <com.android.launcher3.Workspace
    25             android:id="@+id/workspace"
    26             android:layout_width="match_parent"
    27             android:layout_height="match_parent"
    28             launcher:defaultScreen="@integer/config_workspaceDefaultScreen"
    29             launcher:pageIndicator="@+id/page_indicator"></com.android.launcher3.Workspace>
    30 
    31         <!-- DO NOT CHANGE THE ID -->
    32         <include
    33             android:id="@+id/hotseat"
    34             layout="@layout/hotseat"
    35             
    36             android:layout_width="match_parent"
    37             android:layout_height="match_parent" />
    38 
    39         <include
    40             android:id="@+id/overview_panel"
    41             layout="@layout/overview_panel"
    42             android:visibility="gone" />
    43 
    44         <!-- Keep these behind the workspace so that they are not visible when
    45              we go into AllApps -->
    46         <include
    47             android:id="@+id/page_indicator"
    48             layout="@layout/page_indicator"
    49             android:layout_width="wrap_content"
    50             android:layout_height="wrap_content"
    51             android:layout_gravity="center_horizontal" />
    52 
    53         <include
    54             android:id="@+id/search_drop_target_bar"
    55 
    56             layout="@layout/search_drop_target_bar" />
    57 
    58         <include
    59             android:id="@+id/widgets_view"
    60             layout="@layout/widgets_view"
    61             android:layout_width="match_parent"
    62             android:layout_height="match_parent"
    63             android:visibility="invisible" />
    64 
    65         <include
    66             android:id="@+id/apps_view"
    67             layout="@layout/all_apps"
    68             android:layout_width="match_parent"
    69             android:layout_height="match_parent"
    70             android:visibility="invisible" />
    71     </com.android.launcher3.DragLayer>
    72 
    73     <ViewStub
    74         android:id="@+id/launcher_overlay_stub"
    75         android:layout_width="match_parent"
    76         android:layout_height="match_parent"
    77         android:inflatedId="@+id/launcher_overlay"
    78         android:layout="@layout/launcher_overlay" />
    79 </com.android.launcher3.LauncherRootView>

    SearchDropTargetBar

    屏幕最上方有个搜索框,在我们拖动图标的时候,搜索框会替换成“删除“

    Workspace

    就是屏幕上左右滑的好几屏幕的容器

    CellLayout

    Workspace里面可以滑动的单独一屏,CellLayout负责图标和小部件的显示和整齐摆放。

    PageIndicator

    滑动屏幕的时候看见下方的指示器

    Hotseat

    用来放置比较常用的应用,比如拨号,短信,相机等。

    下面介绍几个类

    CellLayout 

    mCountX 和 mCountY   分别表示 “x方向icon的个数” 和 “y方向icon的个数 

    mOccupied 二维数组用来标记每个cell是否被占用,内部类CellInfo为静态类,其对象用于存储cell的基本信息。 

    DeviceProfile  

    设置各元素布局的padding  。修改workspace的padding使用getWorkspacePadding方法。

     1     /** Returns the workspace padding in the specified orientation */
     2     Rect getWorkspacePadding(boolean isLayoutRtl) {
     3         Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
     4         Rect padding = new Rect();
     5         if (isLandscape && transposeLayoutWithOrientation) {
     6             // Pad the left and right of the workspace with search/hotseat bar sizes
     7             if (isLayoutRtl) {
     8                 padding.set(hotseatBarHeightPx, edgeMarginPx,
     9                         searchBarBounds.width(), edgeMarginPx);
    10             } else {
    11                 padding.set(searchBarBounds.width(), edgeMarginPx,
    12                         hotseatBarHeightPx, edgeMarginPx);
    13             }
    14         } else {
    15             if (isTablet) {
    16                 // Pad the left and right of the workspace to ensure consistent spacing
    17                 // between all icons
    18                 float gapScale = 1f + (dragViewScale - 1f) / 2f;
    19                 int width = getCurrentWidth();
    20                 int height = getCurrentHeight();
    21                 int paddingTop = searchBarBounds.bottom;
    22                 int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
    23                 int availableWidth = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) +
    24                         (inv.numColumns * gapScale * cellWidthPx)));
    25                 int availableHeight = Math.max(0, height - paddingTop - paddingBottom
    26                         - (int) (2 * inv.numRows * cellHeightPx));
    27                 padding.set(availableWidth / 2, paddingTop + availableHeight / 2,
    28                         availableWidth / 2, paddingBottom + availableHeight / 2);
    29             } else {
    30                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
    31 
    32                 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
    33                         searchBarBounds.bottom,
    34                         desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
    35                         hotseatBarHeightPx + pageIndicatorHeightPx);
    36 
    37                 
    38             }
    39         }
    40         return padding;
    41     }

    比如我要将workspace里图标顶部不留空隙,需要设置padding.set的第二个参数为0.

    1 padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
    2                         0,//searchBarBounds.bottom, 
    3                         desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
    4                         hotseatBarHeightPx + pageIndicatorHeightPx);

    InvariantDeviceProfile

     一些不变的设备相关参数管理类,landscapeProfile 和 portraitProfile为横竖屏模式的DeviceProfile。 

    getPredefinedDeviceProfiles方法 负责加载在不同设备上不同的布局,和图标大小等。

     1 ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
     2         ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
     3         // width, height, #rows, #columns, #folder rows, #folder columns,
     4         // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
     5         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
     6                 255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
     7         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
     8                 255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
     9         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
    10                 275, 420,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
    11         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
    12                 255, 450,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
    13         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
    14                 296, 491.33f, 4, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
    15         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
    16                 335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
    17 
    18        
    19 
    20         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
    21                 359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
    22         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
    23                 406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
    24         // The tablet profile is odd in that the landscape orientation
    25         // also includes the nav bar on the side
    26         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
    27                 575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
    28         // Larger tablet profiles always have system bars on the top & bottom
    29         predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
    30                 727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
    31         predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
    32                 1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_4x4));
    33         return predefinedDeviceProfiles;
    34     }

    比如我在上面代码的17行加入下列代码,将Hotseat设置成3格,图标大小为72dp

    1         predefinedDeviceProfiles.add(new InvariantDeviceProfile("MX 4",
    2                 359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 3, 72, R.xml.default_workspace_4x4));

    由于launcher是有许多自定义控件构成的,这里涉及到onMesure,onLayout,onDraw方法的复写

    onMesure方法顾名思义,主要是用来重新测量自定义控件的高度和宽度,就是设置它的dimesion,一般所有自定义VIEW都需要复写这个方法。

    onLayout则主要是ViewGroup需要复写这个方法,其作用给这个ViewGroup下子View布局好显示的位置。

    onDraw则是需要真真正正画出内容的控件需要复写的方法,比如textview,或者其子类,其最终利用一个很重要的类Canvas的对象来实现一系列的画图,比如canvas.drawcircle,canvas.drawline.

  • 相关阅读:
    通过Spring使用远程访问和web服务
    mongoDB id 导出,dump,sed,count,mysql import等用法示例
    Spring属性占位符 PropertyPlaceholderConfigurer
    关于Spring管理的类如何创建对象
    spring中反射机制和注入的使用
    Spring 反射注入+全注解注入
    Spring 注解@Component,@Service,@Controller,@Repository
    @Transactional spring 配置事务 注意事项
    Spring 注解Autowired自动注入bean异常解决
    Spring事务的传播行为 @Transactional
  • 原文地址:https://www.cnblogs.com/l2rf/p/5850341.html
Copyright © 2011-2022 走看看