现在,我将每个 XML 布局文件都存储在 'res/layout' 文件夹中,因此管理小型项目是可行且简单的,但是当有大型和重型项目的情况下,则应该有一个层次结构和布局文件夹内需要的子文件夹。
例如
layout
-- layout_personal
-- personal_detail.xml
-- personal_other.xml
--layout_address
-- address1.xml
-- address2.xml
就像同样的方式,我们希望为大型应用程序提供子文件夹,那么在 Android 项目中有没有办法做到这一点?
我可以在 layout 文件夹中创建 layout-personal 和 layout_address 子文件夹,但是当需要使用 R.layout._______ 访问 XML 布局文件时,当时没有任何 XML 布局弹出窗口菜单。
你可以用 gradle 做到这一点。我制作了一个 demo project 来展示如何。
诀窍是使用 gradle 的 merge multiple resource folders 功能,并设置 res 文件夹以及 sourceSets 块中的嵌套子文件夹。
怪癖是您不能在声明该文件夹的子资源文件夹之前声明容器资源文件夹。
下面是演示中 build.gradle 文件中的 sourceSets 块。请注意,首先声明子文件夹。
sourceSets {
main {
res.srcDirs =
[
'src/main/res/layouts/layouts_category2',
'src/main/res/layouts',
'src/main/res'
]
}
}
https://i.stack.imgur.com/yzj01.png
此外,您的实际资源文件(png、xml 布局等)的直接父级仍然需要与 specification 对应。
答案是不。
我想提请您注意这本书Pro Android 2,它指出:
还值得注意的是有关资源的一些限制。首先,Android 仅支持 res 下预定义文件夹中的文件的线性列表。例如,它不支持 layout 文件夹下的嵌套文件夹(或 res 下的其他文件夹)。其次,assets文件夹和res下的raw文件夹有一些相似之处。两个文件夹都可以包含原始文件,但原始文件中的文件被视为资源,资产中的文件不是。请注意,由于 assets 文件夹的内容不被视为资源,因此您可以在其中放置任意层次的文件夹和文件。
raw
视为资源,您可以获得依赖于密度/方向/版本/等的条带化,而对于 assets
,您必须手动执行此操作。
我只是想为遇到麻烦的人添加 eskis 的绝妙答案。 (注意:这只会起作用,并且看起来像“项目”视图中的单独目录,不幸的是,不是“android”视图。)
用以下方法测试。 BuildToolsVersion = 23.0.0 gradle 1.2.3 & 1.3.0
这就是我如何让我的项目与一个已经建成的项目一起工作。
将所有 XML 文件从布局目录中复制出来,并将它们放入桌面上的目录或其他地方进行备份。删除整个布局目录(确保备份了步骤 1 中的所有内容!!!)右键单击 res 目录并选择新建 > 目录。将此新目录命名为“布局”。 (这可以是您想要的任何内容,但它不会是稍后出现的“片段”目录或“活动”目录)。右键单击新的“布局”目录并选择新建 > 目录。 (这将是您将在其中拥有的 XML 文件类型的名称,例如“片段”和“活动”)。右键单击“片段”或“活动”目录(注意:这不一定是“片段”或“活动”,这只是我用作示例的内容)并再次选择新>目录并命名此目录“布局”。 (注意:这必须命名为“布局”!!!非常重要)。将所需的 XML 文件从您在桌面上创建的备份中放入新的“布局”目录中。对任意数量的自定义目录重复步骤 5 - 7。完成后,进入您的模块 gradle.build 文件并创建一个像这样的 sourceSets 定义...(确保 'src/main/res/layouts' 和 'src/main/res' 始终是底部两个!! !! 就像我在下面展示的那样)。 sourceSets { main { res.srcDirs = [ 'src/main/res/layouts/activities', 'src/main/res/layouts/fragments', 'src/main/res/layouts/content', 'src/main/ res/layouts', 'src/main/res' ] } } 利润 $$$$
但说真的..这就是我让它工作的方式。如果有人有任何问题,请告诉我。我可以尝试提供帮助。
图片比文字更有价值。
https://i.stack.imgur.com/C1c9B.png
layout-v21
等布局目录呢?
'src/main/res/layouts/content'
,此配置的路径为 'src/main/res/layouts/content/layout'
不可能,但布局文件夹按名称排序。所以,我在布局文件名前加上我的包名。例如对于“购买”和“玩”两个包:
buying_bought_tracks.xml
buying_buy_tracks.xml
playing_edit_playlist.xml
playing_play_playlist.xml
playing_show_playlists.xml
我使用 Android Studio 的 Android File Grouping 插件。它实际上不允许您创建子文件夹,但它可以显示您的文件和资源,因为它们位于不同的文件夹中。这正是我想要的。
您可以通过以下方式安装“Android File Grouping”插件
视窗:
Android Studio -> 文件 -> 设置 -> 插件。
苹果电脑:
Android Studio -> Android Studio 选项卡(左上) -> 首选项 -> 插件 -> 安装 JetBrains 插件..
对于 Mac,我能够对其进行测试,但无法搜索插件。所以我从 here 下载了插件,并使用了上述设置中的 Install plugin from disk
选项。
我认为解决这个问题的最优雅的解决方案(鉴于不允许使用子文件夹)是在文件名之前加上您将其放置在其中的文件夹的名称。例如,如果您有一堆 Activity、Fragment 或称为“places”的一般视图的布局,那么您应该在其前面加上 places_my_layout_name。至少这解决了以更容易在 IDE 中找到它们的方式组织它们的问题。这不是最棒的解决方案,但总比没有好。
小问题
我可以按照这个问题的 top answer 来实现子文件夹。
但是,随着项目变得越来越大,您将拥有许多子文件夹:
sourceSets {
main {
res.srcDirs =
[
'src/main/res/layouts/somethingA',
'src/main/res/layouts/somethingB',
'src/main/res/layouts/somethingC',
'src/main/res/layouts/somethingD',
'src/main/res/layouts/somethingE',
'src/main/res/layouts/somethingF',
'src/main/res/layouts/somethingG',
'src/main/res/layouts/somethingH',
'src/main/res/layouts/...many more',
'src/main/res'
]
}
}
问题不大,但是:
它不漂亮,因为列表变得很长。
每次添加新文件夹时,您都必须更改 app/build.gradle。
改进
所以我写了一个简单的 Groovy 方法来抓取所有嵌套的文件夹:
def getLayoutList(path) {
File file = new File(path)
def throwAway = file.path.split("/")[0]
def newPath = file.path.substring(throwAway.length() + 1)
def array = file.list().collect {
"${newPath}/${it}"
}
array.push("src/main/res");
return array
}
将此方法粘贴到 app/build.gradle
中的 android {...}
块之外。
如何使用
对于这样的结构:
<project root>
├── app <---------- TAKE NOTE
├── build
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
像这样使用它:
android {
sourceSets {
main {
res.srcDirs = getLayoutList("app/src/main/res/layouts/")
}
}
}
如果你有这样的结构:
<project root>
├── my_special_app_name <---------- TAKE NOTE
├── build
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
您将像这样使用它:
android {
sourceSets {
main {
res.srcDirs = getLayoutList("my_special_app_name/src/main/res/layouts/")
}
}
}
解释
getLayoutList()
将 a relative path
作为参数。 relative path
相对于项目的根目录。因此,当我们输入 "app/src/main/res/layouts/"
时,它会将所有子文件夹的名称作为一个数组返回,这将与以下内容完全相同:
[
'src/main/res/layouts/somethingA',
'src/main/res/layouts/somethingB',
'src/main/res/layouts/somethingC',
'src/main/res/layouts/somethingD',
'src/main/res/layouts/somethingE',
'src/main/res/layouts/somethingF',
'src/main/res/layouts/somethingG',
'src/main/res/layouts/somethingH',
'src/main/res/layouts/...many more',
'src/main/res'
]
这是带有注释以供理解的脚本:
def getLayoutList(path) {
// let's say path = "app/src/main/res/layouts/
File file = new File(path)
def throwAway = file.path.split("/")[0]
// throwAway = 'app'
def newPath = file.path.substring(throwAway.length() + 1) // +1 is for '/'
// newPath = src/main/res/layouts/
def array = file.list().collect {
// println "filename: ${it}" // uncomment for debugging
"${newPath}/${it}"
}
array.push("src/main/res");
// println "result: ${array}" // uncomment for debugging
return array
}
希望能帮助到你!
setContentView(R.layout.Admin.admin_home .)
Admin.admin_home 时它具有 admin_home 布局未解决
R.layout.admin_home
。该脚本应该能够自动为您选择名称。让我知道你是否可以让它工作。
array.push("src/main/res");
更改为 def res="src/main/res";
array.push(res);
后,因为我有一个错误,因为 push 想要 Gstring 参数而不是 String one。如果有人而不是我发现了这个错误,你可以编辑它
// uncomment for debugging
取消注释这些行,然后检查输出 src/main/res/layouts/<your_layout_files>
是否被正确检测到?
现在使用 Android Studio 和 Gradle,您可以在项目中拥有多个资源文件夹。不仅可以组织您的布局文件,还可以组织任何类型的资源。
它不完全是一个子文件夹,但可能会分隔您的应用程序的各个部分。
配置是这样的:
sourceSets {
main {
res.srcDirs = ['src/main/res', 'src/main/res2']
}
}
检查 documentation。
clean
才能看到它反映在应用程序上。
现在我们可以轻松使用名为“Android File Grouping”的 JetBrains 插件
看看这个链接
https://i.stack.imgur.com/nSdnQ.png
Android Studio
中分组
我这样做的一种方法是在项目中与实际 res 文件夹处于同一级别创建一个单独的 res 文件夹,然后您可以在您的应用程序 build.gradle 中使用它
android {
//other stuff
sourceSets {
main.res.srcDirs = ['src/main/res', file('src/main/layouts').listFiles()]
}
}
https://i.stack.imgur.com/zLGhp.png
那么新 res 文件夹的每个子文件夹都可以是与每个特定屏幕或应用程序中的某些内容相关的内容,并且每个文件夹都有自己的 layout
/ drawable
/ values
等,以保持内容井井有条,您无需更新像其他一些答案一样需要手动 gradle 文件(只需在每次添加新资源文件夹时同步您的 gradle 以便它知道它,并确保在添加 xml 文件之前添加相关的子文件夹)。
选中将文件夹层次结构转换为单个文件夹的 Bash Flatten Folder script
如果您在批准的答案中使用该方法,并且想稍微改进一下,那么像这样更改 gradle 设置:
sourceSets {
main {
res.srcDirs = [
file("src/main/res/layouts/").listFiles(),
"src/main/res/layouts",
"src/main/res"
]
}
}
所以如果你添加更多的文件夹和布局,你不需要回到这里附加一长串的源文件夹,让 gradle 为你获取所有的文件夹。
如果您在 linux 或 mac 机器上进行开发,一种解决方法是创建包含指向您的布局文件的符号链接的子文件夹。只需使用带有 -s 的 ln 命令
ln -s PATH_TO_YOUR_FILE
问题在于,您的 Layout 文件夹仍然包含所有 .xml 文件。但是您可以通过使用子文件夹来选择它们。这是最接近你想要的东西。
我刚刚读到,如果您使用的是 Vista 或更高版本,这也可能适用于 Windows。有这个 mklink
命令。自己google一下,没用过。
另一个问题是,如果您打开了文件并尝试再次打开它,插件会抛出 NULL 指针异常。但它不会挂断。
虽然针对多个资源集的所有建议都可能有效,但问题是 Android Studio Gradle 插件的当前逻辑不会在资源文件针对嵌套资源集进行更改后更新它们。当前实现尝试使用startsWith()检查资源目录,因此嵌套的目录结构(即src/main/res/layout/layouts和src/main/res/layout/layouts_category2)将选择src/main/res /layout/layouts 始终如一,从不真正更新更改。最终结果是您每次都必须重建/清理项目。
我在 https://android-review.googlesource.com/#/c/157971/ 提交了一个补丁来帮助解决问题。
@eski 的最佳答案很好,但是代码使用起来并不优雅,所以我在 gradle 中编写了一个 groovy 脚本以供一般使用。它适用于所有构建类型和产品风格,不仅可以用于布局,还可以为任何其他资源类型(如可绘制)添加子文件夹。代码如下(放在项目级gradle文件的android
块中):
sourceSets.each {
def rootResDir = it.res.srcDirs[0]
def getSubDirs = { dirName ->
def layoutsDir = new File(rootResDir, dirName)
def subLayoutDirs = []
if (layoutsDir.exists()) {
layoutsDir.eachDir {
subLayoutDirs.add it
}
}
return subLayoutDirs
}
def resDirs = [
"anims",
"colors",
"drawables",
"drawables-hdpi",
"drawables-mdpi",
"drawables-xhdpi",
"drawables-xxhdpi",
"layouts",
"valuess",
]
def srcDirs = resDirs.collect {
getSubDirs(it)
}
it.res.srcDirs = [srcDirs, rootResDir]
}
实践中怎么做?
例如,我想为 layout
创建名为 activity
的子文件夹,在 resDirs
变量中添加一个任意名称的字符串,例如 layouts
,那么布局 xml 文件应该放在 res\layouts\activity\layout\xxx.xml
中。
如果我想为 drawable
创建名为 selectors
的子文件夹,在 resDirs
变量中添加一个任意名称的字符串,例如 drawables
,那么可绘制的 xml 文件应该放在 res\drawables\selectors\drawable\xxx.xml
中。
layouts
和 drawables
等文件夹名称在 resDirs
变量中定义,可以是任何字符串。您创建的所有子文件夹,例如 activity
或 selectors
都被视为与 res
文件夹相同。所以在 selectors
文件夹中,我们必须另外创建 drawable
文件夹并将 xml 文件放在 drawable
文件夹中,这样 gradle 才能正常识别 xml 文件为可绘制。
第 1 步:右键单击布局 - 在资源管理器中显示
第二步:打开layout文件夹,直接创建子文件夹:layout_1, layout_2 ...
第三步:打开layout_1创建文件夹布局(注:必填名称为layout),打开layout_2文件夹创建布局子目录(注:必填名称为layout)...
第四步:将xml文件复制到layout_1和layout_2的layout子目录中
第 5 步:在 buid.grade(模块应用程序)中运行代码并立即点击同步:
sourceSets {
main {
res.srcDirs =
[
'src / main / res / layout / layout_1'
'src / main / res / layout / layout_2',
'src / main / res'
]
}
}
第 6 步:总结:以上所有步骤仅有助于集群文件夹并以“项目”模式显示,而“安卓”模式将正常显示。
所以我认为命名前缀可能与集群文件夹一样有效。
Project
模式。我不明白子文件夹在哪里消失(在 Android
模式下)。
好吧,简短的回答是否定的。但是您绝对可以拥有多个 res
文件夹。我认为,这与拥有 layout
文件夹的子文件夹一样接近。 Here's 你是怎么做的。
最佳答案有几个缺点:您必须添加新的布局路径,AS 将新资源放置到 res\layouts
文件夹而不是 res\values
。
结合我写的几个答案:
sourceSets {
main {
res.srcDirs =
[
'src/main/res',
file("src/main/res/layouts/").listFiles(),
'src/main/res/layouts'
]
}
}
我用这篇文章制作了文件夹:http://alexzh.com/tutorials/how-to-store-layouts-in-different-folders-in-android-project/。为了创建子文件夹,你应该使用这个菜单:New >文件夹 >水库文件夹。
更新
几周后,我发现 Android Studio 没有注意到资源的变化。因此,出现了一些奇怪的错误。例如,布局继续显示旧尺寸、边距。有时 AS 找不到新的 XML 文件(尤其是在运行时)。有时它会混合 view id
(对另一个 XML 文件的引用)。通常需要按 Build > Clean Project
或 Build > Rebuild Project
。阅读Rebuild required after changing xml layout files in Android Studio。
res
文件夹,因为 AS 不完全支持将资源划分为文件夹。可能我会更改此答案甚至删除。但是,当您说在 SO 上提供解决方案不是一种可接受的方式时,您是什么意思?
不能有子目录(很容易),但您可以有其他资源文件夹。很惊讶没有人提到它,但要保留默认资源文件夹,并添加更多:
sourceSets {
main.res.srcDirs += ['src/main/java/XYZ/ABC']
}
在一个模块中,要拥有风味、风味资源(布局、值)和风味资源资源的组合,要记住的主要有两件事:
在 res.srcDirs 中添加资源目录进行风味时,请记住,在其他模块中,甚至在同一模块的 src/main/res 中,也会添加资源目录。因此,使用附加分配 (+=) 的重要性,以免用新分配覆盖所有现有资源。声明为数组元素的路径是包含资源类型的路径,即资源类型是一个res文件夹通常包含的所有子目录,如color、drawable、layout、values等。名称可以更改 res 文件夹的名称。
一个示例是使用路径 "src/flavor/res/values/strings-ES"
,但注意实践层次结构必须具有子目录 values
:
├── module
├── flavor
├── res
├── values
├── strings-ES
├── values
├── strings.xml
├── strings.xml
该框架准确地按类型识别资源,这就是为什么不能省略通常已知的子目录的原因。
另请记住,风味中的所有 strings.xml
文件将形成一个联合,因此资源不能被复制。反过来,形成风味文件的这个联合在模块的主模块之前具有更高的优先级。
flavor {
res.srcDirs += [
"src/flavor/res/values/strings-ES"
]
}
将 strings-ES
目录视为包含资源类型的自定义资源。
总帐
不定期副业成功案例分享
R.layout.list_item
来自movies
或cinemas
文件夹,因此仍然适用平面命名。build:gradle:0.14.4
和buildToolsVersion "21.1.1"
。URI is not registered
问题的方法。