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.

  • 相关阅读:
    237. Delete Node in a Linked List
    430. Flatten a Multilevel Doubly Linked List
    707. Design Linked List
    83. Remove Duplicates from Sorted List
    160. Intersection of Two Linked Lists
    426. Convert Binary Search Tree to Sorted Doubly Linked List
    142. Linked List Cycle II
    类之间的关系
    初始化块
    明确类和对象
  • 原文地址:https://www.cnblogs.com/l2rf/p/5850341.html
Copyright © 2011-2022 走看看