通过编辑 AOSP 将 Android 导航栏放在侧面

2024-04-12

我想通过编辑 AOSP 将导航栏(具有后退、主页和菜单等系统软键。而不是导航抽屉!)放在(右侧)侧,如下所示。

+-------------------------------------------------+---+
| Status bar (always)                             |   |
+-------------------------------------------------+ N |
| (Layout with background drawable)               | a |
| +---------------------------------------------+ | v |
| | Title/Action bar (optional)                 | |   |
| +---------------------------------------------+ | B |
| | Content, vertical extending                 | | a |
| |                                             | | r |
| +---------------------------------------------+ |   |
+-------------------------------------------------+---+

到目前为止我假设RenderSessionImpl.java https://android.googlesource.com/platform/frameworks/base/+/android-4.2.2_r1/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java是要编辑以完成此操作的文件,因为它呈现的屏幕布局取决于给定的屏幕方向值。

我找到了下一个片段并编辑了方向参数(水平 -> 垂直),这样它将创建一个水平布局,导航栏位于右侧。

if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
        mNavigationBarSize > 0) {
    // system bar
    try {
        NavigationBar navigationBar = new NavigationBar(context,
                hardwareConfig.getDensity(), LinearLayout.VERTICAL); // was LinearLayout.HORIZONTAL originallly
        navigationBar.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
        topLayout.addView(navigationBar);
    } catch (XmlPullParserException e) {

    }
}

原始 AOSP 代码片段如下。

/**
 * Inflates the layout.
 * <p>
 * {@link #acquire(long)} must have been called before this.
 *
 * @throws IllegalStateException if the current context is different than the one owned by
 *      the scene, or if {@link #init(long)} was not called.
 */
public Result inflate() {
    checkLock();

    try {

        SessionParams params = getParams();
        HardwareConfig hardwareConfig = params.getHardwareConfig();
        BridgeContext context = getContext();


        // the view group that receives the window background.
        ViewGroup backgroundView = null;

        if (mWindowIsFloating || params.isForceNoDecor()) {
            backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
        } else {
            if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
                /*
                 * This is a special case where the navigation bar is on the right.
                   +-------------------------------------------------+---+
                   | Status bar (always)                             |   |
                   +-------------------------------------------------+   |
                   | (Layout with background drawable)               |   |
                   | +---------------------------------------------+ |   |
                   | | Title/Action bar (optional)                 | |   |
                   | +---------------------------------------------+ |   |
                   | | Content, vertical extending                 | |   |
                   | |                                             | |   |
                   | +---------------------------------------------+ |   |
                   +-------------------------------------------------+---+

                   So we create a horizontal layout, with the nav bar on the right,
                   and the left part is the normal layout below without the nav bar at
                   the bottom
                 */
                LinearLayout topLayout = new LinearLayout(context);
                mViewRoot = topLayout;
                topLayout.setOrientation(LinearLayout.HORIZONTAL);

                try {
                    NavigationBar navigationBar = new NavigationBar(context,
                            hardwareConfig.getDensity(), LinearLayout.VERTICAL);
                    navigationBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    mNavigationBarSize,
                                    LayoutParams.MATCH_PARENT));
                    topLayout.addView(navigationBar);
                } catch (XmlPullParserException e) {

                }
            }

            /*
             * we're creating the following layout
             *
               +-------------------------------------------------+
               | Status bar (always)                             |
               +-------------------------------------------------+
               | (Layout with background drawable)               |
               | +---------------------------------------------+ |
               | | Title/Action bar (optional)                 | |
               | +---------------------------------------------+ |
               | | Content, vertical extending                 | |
               | |                                             | |
               | +---------------------------------------------+ |
               +-------------------------------------------------+
               | Navigation bar for soft buttons, maybe see above|
               +-------------------------------------------------+

             */

            LinearLayout topLayout = new LinearLayout(context);
            topLayout.setOrientation(LinearLayout.VERTICAL);
            // if we don't already have a view root this is it
            if (mViewRoot == null) {
                mViewRoot = topLayout;
            } else {
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
                layoutParams.weight = 1;
                topLayout.setLayoutParams(layoutParams);

                // this is the case of soft buttons + vertical bar.
                // this top layout is the first layout in the horizontal layout. see above)
                mViewRoot.addView(topLayout, 0);
            }

            if (mStatusBarSize > 0) {
                // system bar
                try {
                    StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
                    systemBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mStatusBarSize));
                    topLayout.addView(systemBar);
                } catch (XmlPullParserException e) {

                }
            }

            LinearLayout backgroundLayout = new LinearLayout(context);
            backgroundView = backgroundLayout;
            backgroundLayout.setOrientation(LinearLayout.VERTICAL);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            backgroundLayout.setLayoutParams(layoutParams);
            topLayout.addView(backgroundLayout);


            // if the theme says no title/action bar, then the size will be 0
            if (mActionBarSize > 0) {
                try {
                    FakeActionBar actionBar = new FakeActionBar(context,
                            hardwareConfig.getDensity(),
                            params.getAppLabel(), params.getAppIcon());
                    actionBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mActionBarSize));
                    backgroundLayout.addView(actionBar);
                } catch (XmlPullParserException e) {

                }
            } else if (mTitleBarSize > 0) {
                try {
                    TitleBar titleBar = new TitleBar(context,
                            hardwareConfig.getDensity(), params.getAppLabel());
                    titleBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mTitleBarSize));
                    backgroundLayout.addView(titleBar);
                } catch (XmlPullParserException e) {

                }
            }

            // content frame
            mContentRoot = new FrameLayout(context);
            layoutParams = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            mContentRoot.setLayoutParams(layoutParams);
            backgroundLayout.addView(mContentRoot);

if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
        mNavigationBarSize > 0) {
    // system bar
    try {
        NavigationBar navigationBar = new NavigationBar(context,
                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
        navigationBar.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
        topLayout.addView(navigationBar);
    } catch (XmlPullParserException e) {

    }
}
        }


        // Sets the project callback (custom view loader) to the fragment delegate so that
        // it can instantiate the custom Fragment.
        Fragment_Delegate.setProjectCallback(params.getProjectCallback());

        View view = mInflater.inflate(mBlockParser, mContentRoot);

        // done with the parser, pop it.
        context.popParser();

        Fragment_Delegate.setProjectCallback(null);

        // set the AttachInfo on the root view.
        AttachInfo_Accessor.setAttachInfo(mViewRoot);

        // post-inflate process. For now this supports TabHost/TabWidget
        postInflateProcess(view, params.getProjectCallback());

        // get the background drawable
        if (mWindowBackground != null && backgroundView != null) {
            Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
            backgroundView.setBackground(d);
        }

        return SUCCESS.createResult();
    } catch (PostInflateException e) {
        return ERROR_INFLATION.createResult(e.getMessage(), e);
    } catch (Throwable e) {
        // get the real cause of the exception.
        Throwable t = e;
        while (t.getCause() != null) {
            t = t.getCause();
        }

        return ERROR_INFLATION.createResult(t.getMessage(), t);
    }
}

但屏幕布局没有显示任何差异。对此有何见解?要编辑的文件错误或逻辑错误? 我知道不建议进行这种调整,但我确实需要这样做。


导航栏可以通过编辑放置在右侧PhoneWindowManager.java https://android.googlesource.com/platform/frameworks/base/+/android-4.2.2_r1/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java and 导航栏.xml https://android.googlesource.com/platform/frameworks/base/+/android-4.2.2_r1/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml.

Set mNavigationBarOnBottom在 PhoneWindowManager 中设置为 false 则以下代码将运行。

// PhoneWindowManager.java
// if mNavigationBarOnBottom = false
// Landscape screen; nav bar goes to the right
int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
if (navVisible) {
    mNavigationBar.showLw(true);
    mDockRight = mTmpNavigationFrame.left;
    mRestrictedScreenWidth = mDockRight - mDockLeft;
} else {
    // We currently want to hide the navigation UI.
    mNavigationBar.hideLw(true);
}
if (navVisible && !mNavigationBar.isAnimatingLw()) {
    // If the nav bar is currently requested to be visible,
    // and not in the process of animating on or off, then
    // we can tell the app that it is covered by it.
    mSystemRight = mTmpNavigationFrame.left;
}

这将在右侧而不是底部创建导航栏的框架,现在需要编辑布局以垂直显示系统按钮(navigation_bar.xml)。

<!--  navigation bar for sw600dp (small tablets) -->
<com.android.systemui.statusbar.phone.NavigationBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:background="#FF000000"
    >    
    <FrameLayout android:id="@+id/rot0"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        >    
        <LinearLayout
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:id="@+id/nav_buttons"
            android:animateLayoutChanges="true"
            >    
            <!-- navigation controls -->
            ~
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                android:layout_width="match_parent"
                android:layout_height="128dp"
                android:src="@drawable/ic_sysbar_back"
                systemui:keyCode="4"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_back"
                />
            ~
        </LinearLayout>
    </FrameLayout>
</com.android.systemui.statusbar.phone.NavigationBarView>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过编辑 AOSP 将 Android 导航栏放在侧面 的相关文章

随机推荐

  • Django - 切换模板渲染的语言设置[重复]

    这个问题在这里已经有答案了 可能的重复 Django 切换 对于一段代码 切换语言 以便以一种语言完成翻译 https stackoverflow com questions 5258715 django switching for a b
  • 评估项目“:app”时出现问题。 > 无法对 null 对象调用 getAbsolutePath() 方法

    我面临着 React Native 构建的问题 无法进一步进行 并且在任何地方都找不到解决方案 这是我的 build gradle 文件 import org apache tools ant taskdefs condition Os b
  • 如何在cmd中显示阿拉伯字母

    任何人都可以提供我的解决方案以在cmd中显示阿拉伯字母 我尝试在 cmd 中使用 chcp 1256 和 chcp 62001 但它没有正确显示阿拉伯字母 但是当我在互联网上搜索时 我发现有人说有解决方案 但它需要 Windows 95 或
  • 如何使用 Polars 按值列表过滤 df?

    我有来自 csv 的 Polars df 我尝试按值列表过滤它 list 1 2 4 6 48 df pl read csv bm dat sep new columns cid1 cid2 cid3 lazy filter pl col
  • 有没有办法在 tomcat6 中强制执行部署顺序?

    我的 webapp 文件夹中有 3 场战争 其中两个是建立在第三个的服务之上的 我处于测试环境中 即我无法控制他们的架构 所以我无法改变任何事情 所以 Question 有没有办法在 tomcat 中强制执行部署顺序 我遇到了一个问题her
  • Android:使用 Google API 进行实时导航,还是与 Google 地图通信?

    我知道以前有人问过这个问题 但我找不到满意的答案 是否可以从 Android 可用的 Google API 获取实时方向更新 Google Maps API 仅提供视觉功能 但不提供任何方向功能 Google Directions API
  • 如何将 javax.xml.transform.Source 转换为 InputStream?

    我怎样才能转换javax xml transform Source进入输入流 实施Source is javax xml transform dom DOMSource Source inputSource messageContext g
  • MSVC constexpr 函数“xyz”无法生成常量表达式

    我创建了一个函数 它将多个较小的值连接成一个较大的值 同时保留值的二进制表示 例如构建一个int argb来自多个unsigned char r g b a 我知道我也可以通过改变值来实现这一点 但这不是这个问题的问题 但是 如果我使用该函
  • Rails:用空对象模式替换 try

    在我的大多数应用程序中 我都有一个current user方法 为了避免在类似情况下出现异常current user name where current user is nil rails 提供了try方法 问题是我需要记住使用try无论
  • 声明普通类和类模板的静态数据成员

    我读到在源文件中定义静态数据成员的原因是因为如果它们位于头文件中并且多个源文件包含头文件 定义将多次输出 我可以理解为什么这对于静态常量数据成员来说是一个问题 但是为什么这对于静态数据成员来说是一个问题呢 我不太确定我完全理解如果定义写在头
  • 如何在django过滤器中做小于或等于和大于等于?

    如何在django过滤器中做小于或等于和大于等于 就像 我想获得周围的价值 10 lt val lt 50在 Django 视图中 为此 我在 sql 中使用了一些查询 如下所示 select count from table name w
  • Linux 中的直接内存访问

    我正在尝试直接访问嵌入式 Linux 项目的物理内存 但我不确定如何最好地指定内存供我使用 如果我定期启动设备并访问 dev mem 我就可以轻松地读写任何我想要的位置 然而 在这里 我访问的是可以轻松分配给任何进程的内存 我不想做 我的
  • Google Dataproc 上的 Spark UI 位于何​​处?

    我应该使用什么端口来访问 Google Dataproc 上的 Spark UI 我尝试了端口 4040 和 7077 以及我发现使用的许多其他端口netstat pln 防火墙配置正确 Dataproc 在 YARN 之上运行 Spark
  • 注册 COM 接口的实现

    我是 COM 编程新手 我已经准备好了一个 COM 对象 以及关联的 IClassFactory 但我不太清楚如何注册生成的 DLL 以供其他程序使用 我也不清楚需要携带的 GUID 数量 我尝试注册的 COM 对象实现了 IAudioSe
  • 如何使用 Flutter 编写带有要点的段落?

    使用 HTML 我可以向段落添加项目符号 如下所示 ul li example li li example li li example li ul 如何在 Flutter 中编写要点形式 new Text 如果您不想下载另一个库 例如 fl
  • 使用 sed 仅打印每个段落的第一个单词

    我想知道如何用 sed 单行打印出每个段落的第一个单词 在本例中 段落由 2 个换行符后面的文本定义 e g This is a paragraph with some text Some random text that is not r
  • Xamarin:使用布局的启动屏幕

    我正在尝试为我的 Android 应用程序创建启动屏幕 如此链接所示http developer xamarin com guides android user interface creating a splash screen http
  • 如何在 JLayeredPane 上设置背景颜色?

    我很好奇为什么在 JLayeredPane 上调用 setBackground Color 似乎并没有真正设置背景颜色 我猜这与 JLayeredPane 由于某种原因必须具有透明背景有关 不管怎样 这里有一些代码显示了这个问题 这是在 M
  • ajax请求后如何更改URL?

    我有一个菜单 其中包含一些更新 div 的链接content并执行该函数onSuccess加载后 li Ajax ActionLink Home Index home li li Ajax ActionLink Download Index
  • 通过编辑 AOSP 将 Android 导航栏放在侧面

    我想通过编辑 AOSP 将导航栏 具有后退 主页和菜单等系统软键 而不是导航抽屉 放在 右侧 侧 如下所示 Status bar always N Layout with background drawable a v Title Acti