覆盖 Android 框架中的布局 XML

33

问题

我想要覆盖来自Android命名空间的布局文件,例如R.layout.popup_menu_item_layout(在代码中引用为com.android.internal.R.layout.popup_menu_item_layout)。通过说“覆盖”,我假设在项目中声明一个xml文件,该文件将优先于框架拥有的布局。

请注意,这只是一个示例布局,因此问题涉及到sdk/platforms/android-XX/data/res/layout目录中存在的每个布局。

我尝试过的方法

tools:override

有一个未记录的tools:override标签可用,它可以覆盖特定的资源。请参见答案中的示例,该示例覆盖了来自Design Support Library而非Android框架的值。

tools:override="true"应用于布局的根标记将不会生效。


XML布局引用 - refs.xml

this所述,声明一个/values/目录下的refs.xml文件,并包含以下内容:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item type="layout" name="activity_main">@layout/activity_second</item>
</resources>

一旦使用activity_main.xml,将会引用activity_second.xml。有一个答案建议使用这种技术来替换Snackbar的布局。

这也不会生效。

问题

是否有合法的方法可以覆盖/替换Android包中的布局文件?


2
如果您正在扩展布局,则只需修改代码以使用替代项。如果您尝试替换其他内容正在扩展的布局(例如PopupMenu),则据我所知是不可能的。您可以尝试派生该类并创建自己的版本,然后使用您的替换布局。 - CommonsWare
1
通常那些API都隐藏在公共API的深处(PopupMenu使用SomeClassASomeClassA又使用SomeClassB,最终导致这个布局被充气),这意味着我必须坚持多级反射,希望我能找到足够的接缝来实现所需的效果。不过还是谢谢你的回复。 - azizbekian
2
最终,你会不得不分叉它们。要么你获得了一整套的类,要么你碰到了某些不能分叉的东西(例如android.view.View和带有native方法的东西)。对于后者,你只能寻找其他解决方案来解决整体问题。因此,例如我通过这种方式分支了Android 7.0的网络安全配置的全部内容,丢弃了在旧设备上无法使用的部分,作为创建后移的一部分。 - CommonsWare
2
你尝试过将布局文件直接复制到代码库中吗?名称必须保持不变,如果有多个布局大小,也需要注意复制。您还需要解决所有出现的尺寸错误。我记得当我需要修改来自Google Cast支持库(媒体控制器)的活动布局时,这种方法对我有效,这样我就能够摆脱双窗格布局并更改颜色、品牌等所有内容。 - Andrej Jurkin
1
你是否尝试在你的项目中添加一个名为“com.android.internal”的模块库,它将生成你自己的com.android.internal.R,并且无论编译如何解决依赖冲突,也许你能够覆盖布局链接? - smora
显示剩余11条评论
4个回答

21

我知道这是一个老问题,但是我也想用自己的布局覆盖库中的布局,这是我实现的方法。

需要覆盖的布局名为design_bottom_navigation_item

在refs.xml中添加如下内容:

<resources xmlns:tools="http://schemas.android.com/tools">
    <item name="design_bottom_navigation_item" type="layout" tools:override="true">@layout/bottom_navigation_item</item>
</resources>

这里有四个部分需要解释。

  • Name:这是你想要覆盖的布局文件的名称。
  • Type:你想要覆盖的资源类型,在本例中为布局文件。
  • tools:override:这是告诉Android Studio用自己的布局文件覆盖库中的布局文件的方法。
  • Value:这是你指定想要使用的替代资源的地方。

你可以用这种方法来覆盖任何资源类型。


2
你所提到的布局不是来自框架,而是来自一个库,你将其附加到你的项目中(准确地说是设计支持库)。不幸的是,你的回答对我没有帮助,因为按照你提到的方法,你无法覆盖例如R.layout.popup_menu_item_layout。你的解决方案已经在问题本身中指出。谢谢。 - azizbekian
完美地解决了第三方库中有缺陷的XML布局替换问题! - isabsent

0

您正在尝试在应用程序本身上自定义SDK,而且是在运行时。

这不是它的工作方式。

如果您在项目中使用SDK(任何技术),并且需要修改某些行为,则会调整此SDK,然后使用此新定制版本编译您的项目。
尝试在运行时进行修改不是一个好主意。
您将面临多个问题(向后兼容性、安全触发器、TREBLE不兼容性、依赖项问题等)

您有4种可能实现您想要的内容:

  1. 制作自己的Android ROM,在其中应用您的修改
  2. 使用带有标签的虚拟xmlObject复制您需要修改的资源,在应用程序的onPostCreate之后,您将能够在膨胀时修改。您可以概括此行为,并模拟SDK覆盖。
  3. 制作自己的SDK :)
  4. 多级反射,但是,没有稳定版本可以成功

当然,这些解决方案都不适用于公共应用程序。


0

不知道你的问题是否已经解决,但是这个问题的简单解决方案是创建一个与框架相同的布局名称的新布局(在这种情况下是popup_menu_item_layout)。然后去安卓谷歌源代码中复制xml内容popup_menu_item_layout

这样你就可以自定义任何你想要的东西。但是请记住不要更改任何视图的ID。


0
你想做什么?
如果你只是想更改菜单项的外观,可以尝试以下步骤:
1. 创建一个自定义的 MyMenuAdapter 类,继承 MenuAdapter。 2. 重写 getView 方法,从你的适配器中返回视图。

注意,这只是一个示例布局,因此问题涉及sdk/platforms/android-XX/data/res/layout目录中存在的每个布局。很遗憾,您的答案甚至没有接近正确答案。 - azizbekian
哦...每个文件。我错过了那个。所以,基本上你想要替换使用的内部布局文件。这就是所谓的定制固件,不能在不重新编译操作系统的情况下完成。如果你只是为了你的应用程序而这样做 - 你将不得不替换所有的文件,重新编译并在你的应用程序中使用新代码,并且不要忘记使用一个不同的包名,例如:com.myapp.repackaged.com.layout.internal或任何其他名称。 - gvaish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接