Android7.0开发实现Launcher3去掉应用抽屉的方法详解

本文实例讲述了Android7.0开发实现Launcher3去掉应用抽屉的方法。分享给大家供大家参考,具体如下:

年初做过一个项目,有一个需求就是需要将桌面变为单层不需要二级菜单。最近几次有小伙伴有这个问我这个解决办法。现在我将分享给大家。

先上效果图:

 

功能分解

1. 去除Allapp键,调整HotSeat布局
2. 将所有应用摆在launcher第一层
3. 去掉长按时删除选项

解决方案

一、设置总开关

按照6.0 Launcher3 的模式,添加一个开关,控制是否去掉抽屉。
LauncherAppState类:单例模式,主要在启动的时候用,他初始化了一些对象,并且注册了广播监听器和ContentObserver。为了能灵活切换模式,在此类中添加静态开关。

Launcher3\src\com\android\launcher3\LauncherAppState.java:

public static boolean isDisableAllApps() {
    // Returns false on non-dogfood builds.
    return android.os.SystemProperties.get("ro.wind.launcher3.ishome2","0").equals("1");
}

二、Allapp键的加载

在HotSeat里面去掉Allapp键的加载 ,屏蔽isAllAppsButtonRank()占用allapp位置。

1) 不再占用allapp位置

2) 在加载Workspace时,会留出HotSeat的第三个位置给allapp按钮,若不取消该位置的占用,在HotSeat加载时会留出空位。HotSeat的初始化在HotSeat.java中

Launcher3\src\com\android\launcher3\HotSeat.java –>isAllAppsButtonRank():

public boolean isAllAppsButtonRank(int rank) {
    //添加 @{
    if (LauncherAppState.isDisableAllApps()) {
      return false;
      }
    //添加 @}
    return rank == mAllAppsButtonRank;
}

3) Home2没有抽屉,所以不需要allapp按钮。在HotSeat里面去掉Allapp键的加载,在HotSeat.java 的void resetLayout()中初始化HotSeat布局。在Home2时停止加载Allapp按钮。

Launcher3\src\com\android\launcher3\HotSeat.java –>resetLayout():

void resetLayout() {
    mContent.removeAllViewsInLayout();
    //添加 @{
    if(LauncherAppState.isDisableAllApps()){
    //添加 }@
    // Add the Apps button
    Context context = getContext();
    LayoutInflater inflater = LayoutInflater.from(context);
    TextView allAppsButton = (TextView)
        inflater.inflate(R.layout.all_apps_button, mContent, false);
    Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
    mLauncher.resizeIconDrawable(d);
    allAppsButton.setCompoundDrawables(null, d, null, null);
    allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
    allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
    if (mLauncher != null) {
      mLauncher.setAllAppsButton(allAppsButton);
      allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
      allAppsButton.setOnClickListener(mLauncher);
      allAppsButton.setOnLongClickListener(mLauncher);
      allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
    }
    // 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
    int x = getCellXFromOrder(mAllAppsButtonRank);
    int y = getCellYFromOrder(mAllAppsButtonRank);
    CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
    lp.canReorder = false;
    mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
    }
}//别漏了这里的 }

三、数据初始化类中更改HotSeat布局

InvariantDeviceProfile.java Launcher3进行布局初始化的一个类。

在有allapp按钮时HotSeat里Hotseat图标数量为五个,没有allapp按钮时Hotseat图标数量应为四个。

Launcher3\src\com\android\launcher3\InvariantDeviceProfile.java:

1)先加个宏控

//添加 @{
private boolean hasDA = LauncherAppState.isDisableAllApps();
//添加 }@

2)去掉抽屉时,HotSeat的格数为四格,所以不能抛出异常。 ( numHotseatIcons 为偶时不抛异常)

InvariantDeviceProfile( ):

InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
    // Ensure that we have an odd number of hotseat items (since we need to place all apps)
    if (hs % 2 == 0&& !hasDA) {// 在无抽屉情况下不抛异常
      throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
    }
    name = n;
     ...  ...
}

3)去掉抽屉的情况下加载不同的布局

getPredefinedDeviceProfiles() :

ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
    ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
    // width, height, #rows, #columns, #folder rows, #folder columns,
    // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
        255, 300,   2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
        255, 400,   3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
        275, 420,   3, 4, 3, 4, 4, 48, 13, (hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
        255, 450,   3, 4, 3, 4, 4, 48, 13, (hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
        296, 491.33f, 4, 4, 4, 4, 4, 48, 13,(hasDA ? 4 : 5), 48, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
        335, 567,   4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasDA ? 4 : 5), 56, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
        359, 567,   4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13,(hasDA ? 4 : 5), 56, (hasDA ? R.xml.default_workspace_4x4_no_all_apps : R.xml.default_workspace_4x4 )));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
        406, 694,   5, 5, 4, 4, 4, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5));
    // The tablet profile is odd in that the landscape orientation
    // also includes the nav bar on the side
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
        575, 904,   5, 6, 4, 5, 4, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6));
    // Larger tablet profiles always have system bars on the top & bottom
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
        727, 1207,  5, 6, 4, 5, 4, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
        1527, 2527,  7, 7, 6, 6, 4, 100, 20, 7, 72, R.xml.default_workspace_4x4));
    return predefinedDeviceProfiles;
}

5)记得改下 dw_phone_hotseat.xml 的布局 ,因为Hotseat只有5格了。

四、将所有应用放在第一层

launcher3加载流程:进入 LauncherApplication -> LauncherAppState -> 进行初始化环境(通过传递sContext)。进行事件监听&&初始化一些环境。例如:横竖屏、当局语言、像素密度、小部件和快捷图标数据库操作对象、应用图标缓存对象、初始化LauncherMode等。在初始化过后,从Launcher的Oncreate方法入手。mModel.startLoader(mWorkspace.getRestorePage());里加载数据 。在加载完成所有快捷方式后将其余为加载完的应用布局在第一层。

1) 成所有快捷方式后将其余为加载完的应用布局在第一层。

Launcher3\src\com\android\launcher3\LauncherModel.java:

LauncherModel$LoaderTask –> run():

public void run() {
  ... ...
  // Optimize for end-user experience: if the Launcher is up and // running with the
  // All Apps interface in the foreground, load All Apps first. Otherwise, load the
  // workspace first (default).
  keep_running: {
    if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
    loadAndBindWorkspace();
    if (mStopped) {
      LauncherLog.i(TAG, "LoadTask break in the middle, this = " + this);
      break keep_running;
    }
    waitForIdle();
    // second step
    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
    loadAndBindAllApps();
    //添加 @{
    if (LauncherAppState.isDisableAllApps()) {
      verifyApplications();
    }
    //添加 }@
  }
  // Clear out this reference, otherwise we end up holding it until all of the
  // callback runnables are done.
  ... ...
}

添加verifyApplications():

private void verifyApplications() {
    final Context context = mApp.getContext();
    // Cross reference all the applications in our apps list with items in the workspace
    ArrayList<ItemInfo> tmpInfos;
    ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
    synchronized (sBgLock) {
      for (AppInfo app : mBgAllAppsList.data) {
        tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
        if (tmpInfos.isEmpty()) {
          // We are missing an application icon, so add this to the workspace
          added.add(app);
          // This is a rare event, so lets log it
          Log.e(TAG, "Missing Application on load: " + app);
        }
      }
    }
    if (!added.isEmpty()) {
      addAndBindAddedWorkspaceItems(context, added);//7.0 虽然去掉了去抽屉的代码,但留了这个方法给我们。
    }
}

五、有新应用添加时更新Workspace

当安装新应用时,我们需要对左面更新,保证安装的应用添加在第一层上。

Launcher3\src\com\android\launcher3\LauncherModel.java:

LauncherModel$PackageUpdatedTask –> run():

public void run() {
  if (!mHasLoaderCompletedOnce) {
    // Loader has not yet run.
    return;
  }
  final Context context = mApp.getContext();
  ... ...
  if (added != null) {
    // 添加 @{
    if(LauncherAppState.isDisableAllApps()){
        final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);
        addAndBindAddedWorkspaceItems(context, addedInfos);
    }else{
    // 添加 }@
    addAppsToAllApps(context, added);
    }
    for (AppInfo ai : added) {
      addedOrUpdatedApps.put(ai.componentName, ai);
    }
  }
  ... ...
}

六、去掉长按时的删除选项

长按时,不该有删除选项 。

DeleteDropTarget.java: 中更改长按时的监听,开始时直接屏蔽删除按钮,后来发现应用自身发出的快捷方式无法删除 所以做了如下处理。

Launcher3\src\com\android\launcher3\DeleteDropTarget.java –>supportsDrop():

public static boolean supportsDrop(Object info) {
     //添加 @{
    if (LauncherAppState.isDisableAllApps()) {
      if (info instanceof ShortcutInfo) {
        ShortcutInfo item = (ShortcutInfo) info;
        return item.itemType != LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
      }
      return info instanceof LauncherAppWidgetInfo;
    }
    //添加 }@
    return (info instanceof ShortcutInfo)
        || (info instanceof LauncherAppWidgetInfo)
        || (info instanceof FolderInfo);
}

写在最后

到此,Launcher3去掉应用抽屉的改动已经完成。还有很多我们需要去美化的,就比如HotSeat布局自适应等。

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android窗口相关操作技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

(0)

相关推荐

  • Android圆形头像拍照后“无法加载此图片”的问题解决方法(适配Android7.0)

    Feature: 点击选择拍照或者打开相册,选取图片进行裁剪最后设置为圆形头像. Problem: 拍好照片,点击裁剪,弹Toast"无法加载此图片". Solution: 在裁剪的class里加两行代码 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 主要代码如下: public static final S

  • Android7.0上某些PopuWindow出现显示位置不正确问题的解决方法

    本文实例讲述了Android7.0上某些PopuWindow出现显示位置不正确问题的解决方法.分享给大家供大家参考,具体如下: 情景描述: 在andorid7.0及以上系统,点击某个view,本来期待有一个Popuwindow在该view下面弹出(调用PopuWindow.showAsDropDown(view)方法)但结果PopuWindow却弹出在view上方,顶在系统状态栏下面. 原因分析: 在android7.0上,如果不主动约束PopuWindow的大小,比如,设置布局大小为 MATC

  • Android7.0 工具类:DiffUtil详解

    一 概述 DiffUtil是support-v7:24.2.0中的新工具类,它用来比较两个数据集,寻找出旧数据集->新数据集的最小变化量. 说到数据集,相信大家知道它是和谁相关的了,就是我的最爱,RecyclerView. 就我使用的这几天来看,它最大的用处就是在RecyclerView刷新时,不再无脑mAdapter.notifyDataSetChanged(). 以前无脑mAdapter.notifyDataSetChanged()有两个缺点: 1.不会触发RecyclerView的动画(删

  • Android7.0版本影响开发的改进分析

    本文总结分析了Android7.0版本影响开发的改进.分享给大家供大家参考,具体如下: 低电耗模式 会对闹铃.GPS 和 Wi-Fi 扫描 产生限制. 可参考Optimizing for Doze and App Standby 使用GCM来发送和接受消息 后台优化 Android N 删除了三项隐式广播,隐式广播会在后台频繁启动已注册侦听这些广播的应用. 删除这些广播可以显著提升设备性能和用户体验. 侦听网络变化的主线程广播改为: CONNECTIVITY_CHANGE. 对所有应用都无法 发

  • Android7.0 MessageQueue详解

    Android中的消息处理机制大量依赖于Handler.每个Handler都有对应的Looper,用于不断地从对应的MessageQueue中取出消息处理. 一直以来,觉得MessageQueue应该是Java层的抽象,然而事实上MessageQueue的主要部分在Native层中. 自己对MessageQueue在Native层的工作不太熟悉,借此机会分析一下. 一.MessageQueue的创建 当需要使用Looper时,我们会调用Looper的prepare函数: public stati

  • 解决Android7.0更新后无法安装的问题

    最近在我们的应用中加入更新功能,按照往常一样加入代码 if (!apkfile.exists()) { Toast.makeText(mContext, "下载的安装包不存在", Toast.LENGTH_SHORT).show(); return; } Intent install = new Intent(Intent.ACTION_VIEW); install.setDataAndType(Uri.fromFile(apkfile), "application/vnd.

  • 适配android7.0获取文件的Uri的方法

    前言# Android 7.0已经发布很久了,虽然市场份额还不是很高,但是流行起来都是早晚的事,所以适配Android 7.0刻不容缓. Android 7.0 对系统进行了很多的优化:例如文件访问权限,省电,网络,后台等等,其中最突出的就是应用外的Uri访问. 什么时候会用到Uri的应用外访问呢?举一个简单的例子,下载apk更新,这个时候会调用系统功能来安装这个apk,这就是应用外访问文件,需要传入文件的Uri. 但是这样可能会显得不太安全,万一是什么非常重要的文件就糟糕了,所以Android

  • Android7.0开发实现Launcher3去掉应用抽屉的方法详解

    本文实例讲述了Android7.0开发实现Launcher3去掉应用抽屉的方法.分享给大家供大家参考,具体如下: 年初做过一个项目,有一个需求就是需要将桌面变为单层不需要二级菜单.最近几次有小伙伴有这个问我这个解决办法.现在我将分享给大家. 先上效果图:   功能分解 1. 去除Allapp键,调整HotSeat布局 2. 将所有应用摆在launcher第一层 3. 去掉长按时删除选项 解决方案 一.设置总开关 按照6.0 Launcher3 的模式,添加一个开关,控制是否去掉抽屉. Launc

  • python图形开发GUI库pyqt5的基本使用方法详解

    一:安装PyQt5 pip install pyqt5 如果你的系统没有安装pip请阅读我们的另一篇文章 windows下python安装pip方法详解 二:PyQt5简单使用 #!/usr/bin/python3 # -*- coding: utf-8 -*- """ Py40.com PyQt5 tutorial In this example, we create a simple window in PyQt5. author: Jan Bodnar website:

  • Android6.0编程实现双向通话自动录音功能的方法详解

    本文实例讲述了Android6.0编程实现双向通话自动录音功能的方法.分享给大家供大家参考,具体如下: 项目中需要实现基于Android 6.0 的双向通话自动录音功能,在查阅相关android电话状态监听文章以及Git上的开源录音项目后,整理出此文 首先,介绍一下android 电话状态的监听(来电和去电): http://www.jb51.net/article/32433.htm 实现手机电话状态的监听,主要依靠两个类: TelephoneManger和PhoneStateListener

  • vue2.0结合DataTable插件实现表格动态刷新的方法详解

    本文实例讲述了vue2.0结合DataTable插件实现表格动态刷新的方法.分享给大家供大家参考,具体如下: 产品提出的需求是这样的,很普通的一个统计server端task完成率和状态的表格,要自动刷新其中的数据,并且当单个task完成的时候report给server端,看起来好easy好easy的一个需求啊!且听我说完哈! 我这边使用的是框架是vue,表格自然用v-for渲染,然后我们这边分页搜索神马的都是前端弄,也就是说后端只管把一大坨数据塞到前端,然后前端自己组装分页器和完成模糊搜索,所以

  • Android开发教程之调用摄像头功能的方法详解

    本文实例讲述了Android调用摄像头功能的方法.分享给大家供大家参考,具体如下: 我们要调用摄像头的拍照功能,显然 第一步必须加入调用摄像头硬件的权限,拍完照后我们要将图片保存在SD卡中,必须加入SD卡读写权限,所以第一步,我们应该在Android清单文件中加入以下代码 摄像头权限: <uses-permission android:name="android.permission.CAMERA"/> SD卡读写权限: <uses-permission androi

  • asp.net开发sql server转换成oracle的方法详解

    前言 因为前段时间我们公司项目 要把sql server 转oracle,发现网上这方面的资料较少,所以在这里分享一下心得,也记录一下问题,下面话不多说了,来一起看看详细的介绍: 开始我研究了一段时间 然后下载了 oracle 11g 版本 和 PL/SQL(客户端) 和sql server 不同的是 oracle 没有自己的客户端 需要用第三方的软件运行 PL/SQL 就是一个 sqldeveloper 也是一个,PL/SQL 我觉得比较稳定一点.但是2个都安装的话 刚好互补了 oracle

  • 解决Fedora14下eclipse进行android开发,ibus提示没有输入窗口的方法详解

    好不容易搭建好了开发环境,可是不管怎么按Ctr + space,ibus就是不弹出来.用鼠标点吧,上面提示没有输入窗口.真是操蛋!google了一圈也没有解决办法,我是第一个遇到这问题的人么??无奈下,干脆换输入法!将系统自带的ibus换成fcitx输入法,安装步骤为:首先切换到root1,yum install fcitx2, alternatives --config xinputrc会出来提示,会提示共有 4 个程序提供"xinputrc".选择    命令-----------

  • Android开发中Launcher3常见默认配置修改方法总结

    本文实例讲述了Android开发中Launcher3常见默认配置修改方法.分享给大家供大家参考,具体如下: Launcher概述 Launcher是开机完成后第一个启动的应用,用来展示应用列表和快捷方式.小部件等.Launcher作为第一个(开机后第一个启动的应用)展示给用户的应用程序,其设计的好坏影响到用户的体验,甚至影响用户购机的判断.所以很多品牌厂商都会不遗余力的对Launcher进行深度定制,如小米的MIUI.华为的EMUI等.Android默认的Launcher没有过多的定制,更加简洁

  • IOS开发 支持https请求以及ssl证书配置详解

    IOS开发 支持https请求以及ssl证书配置详解 前言: 众所周知,苹果有言,从2017年开始,将屏蔽http的资源,强推https 楼主正好近日将http转为https,给还没动手的朋友分享一二 一.证书准备 1.证书转换 在服务器人员,给你发送的crt证书后,进到证书路径,执行下面语句 // openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der 这样你就可以得到cer类型的证书了.双击,导入电脑. 2.证书放入工程 1.可以直接把转换好

  • iOS开发微信收款到账语音提醒功能思路详解

    一.背景 为了解决小商户老板们在频繁交易中不方便核对.确认到账的痛点,产品MM提出了新版本需要支持收款到账语音提醒功能.这篇文章总结了开发过程中遇到的坑和一些小技巧. 二.技术方案 后台唤醒App 收款到账语音提醒需要收款方在收到款后,播放一段TTS合成语音播报金额,微信在前台时可以通过模板消息将需要播报的金额带下来,再请求TTS数据并播放,但是app在挂起或者被kill掉的情况下要如何请求语音数据并播放呢? iOS提供了两种方式唤醒处于挂起或已经被kill掉的app.分别是Silent Not

随机推荐