提问人:Paresh Mayani 提问时间:2/8/2011 最后编辑:Braian CoronelParesh Mayani 更新时间:12/16/2022 访问量:209056
Android 布局文件夹可以包含子文件夹吗?
Can the Android layout folder contain subfolders?
问:
现在,我将每个 XML 布局文件都存储在“res/layout”文件夹中,因此管理小型项目是可行且简单的,但是当出现大型和重型项目的情况时,布局文件夹内应该需要一个层次结构和子文件夹。
例如
layout
-- layout_personal
-- personal_detail.xml
-- personal_other.xml
--layout_address
-- address1.xml
-- address2.xml
同样,我们希望为大型应用程序提供子文件夹,那么在 Android 项目中有什么方法可以做到这一点吗?
我能够在布局文件夹中创建布局个人和layout_address子文件夹,但是当需要使用 R.layout._______ 访问 XML 布局文件时,此时菜单内没有任何 XML 布局弹出窗口。
答:
答案是否定的。
我想提请您注意这本书 Pro Android 2 它指出:
还值得注意的是一些 有关资源的限制。 首先,Android 仅支持线性 预定义中的文件列表 Res 下的文件夹。例如,它不支持嵌套文件夹 布局文件夹(或其他 res下的文件夹)。
其次,有一些相似之处 在 assets 文件夹和 RAW 之间 Res 下的文件夹。两个文件夹都可以 包含原始文件,但文件 在原始资源中被视为资源 而资产中的文件则不是。
请注意,由于不考虑资产文件夹的内容 资源,可以任意放一个 其中文件夹和文件的层次结构。
评论
raw
assets
如果您在 linux 或 mac 机器上进行开发,一种解决方法是创建子文件夹,其中包含指向布局文件的符号链接。只需将 ln 命令与 -s 一起使用
ln -s PATH_TO_YOUR_FILE
这样做的问题是,您的布局文件夹仍然包含所有 .xml 文件。但是,您可以使用子文件夹来选择它们。这是最接近你想要的东西。
我刚刚读到,如果您使用的是 Vista 或更高版本,这可能也适用于 Windows。有这个命令。只是谷歌一下,我自己从来没有用过。mklink
另一个问题是,如果您打开了文件并尝试再次打开它,则插件会抛出 NULL 指针异常。但它不会挂断。
评论
不可能,但布局文件夹按名称排序。因此,我在布局文件名前面加上我的包名称。例如,对于“购买”和“播放”两个包:
buying_bought_tracks.xml
buying_buy_tracks.xml
playing_edit_playlist.xml
playing_play_playlist.xml
playing_show_playlists.xml
我认为这个问题最优雅的解决方案(鉴于不允许子文件夹)是在文件名前面加上您将其放入其中的文件夹的名称。例如,如果您有一堆用于 Activity、Fragment 或仅称为“places”的一般视图的布局,那么您应该在它前面加上places_my_layout_name。至少这解决了以一种更容易在 IDE 中找到它们的方式组织它们的问题。这不是最令人敬畏的解决方案,但总比没有好。
现在,借助 Android Studio 和 Gradle,您可以在项目中拥有多个资源文件夹。不仅可以组织布局文件,还可以组织任何类型的资源。
它不完全是一个子文件夹,但可能会分隔应用程序的某些部分。
配置如下:
sourceSets {
main {
res.srcDirs = ['src/main/res', 'src/main/res2']
}
}
检查文档。
评论
clean
你可以用 .我做了一个演示项目来展示如何。gradle
诀窍是使用 gradle 合并多个资源文件夹的能力,并在块中设置 res 文件夹以及嵌套子文件夹。sourceSets
怪癖是,在声明容器资源文件夹的子资源文件夹之前,不能声明该文件夹。
下面是演示文件中的块。请注意,子文件夹是首先声明的。sourceSets
build.gradle
sourceSets {
main {
res.srcDirs = [
'src/main/res/layouts/layouts_category2',
'src/main/res/layouts',
'src/main/res'
]
}
}
此外,实际资源文件(png、xml 布局等)的直接父级仍需要与规范相对应。
评论
R.layout.list_item
movies
cinemas
build:gradle:0.14.4
buildToolsVersion "21.1.1"
URI is not registered
选中将文件夹层次结构转换为单个文件夹的 Bash 拼平文件夹脚本
评论
好吧,简短的回答是否定的。但是您绝对可以拥有多个文件夹。我认为,这已经尽可能接近于拥有文件夹的子文件夹。这是你如何做到的。res
layout
评论
虽然针对多个资源集的所有建议都可能有效,但问题在于,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/ 提交了一个补丁,试图帮助解决问题。
评论
我只是想为遇到麻烦的人补充 eskis 的精彩答案。(注意:不幸的是,这只能在“项目”视图中起作用,看起来像单独的目录,而不是“android”视图。
通过以下测试。 BuildToolsVersion = 23.0.0 Gradle 1.2.3 和 1.3.0
这就是我如何让我的项目与一个已经建成的项目一起工作。
- 将所有 XML 文件从布局目录中复制出来,并将它们放入桌面上的目录或其他位置进行备份。
- 删除整个布局目录(确保备份了步骤 1 中的所有内容!!)
- 右键单击 res 目录,然后选择 new > directory。
- 将此新目录命名为“layouts”。(这可以是你想要的任何东西,但它不会是稍后出现的“片段”目录或“活动”目录)。
- 右键单击新的“layouts”目录,然后选择新的>目录。(这将是您将包含的 XML 文件类型的名称,例如,“fragments”和“activities”)。
- 右键单击“fragment”或“activities”目录(注意:这不一定是“fragment”或“activities”,这只是我用作示例的内容),然后再次选择“新建>目录”并将此目录命名为“layout”。(注意:这必须命名为“布局”!!非常重要)。
- 将您想要的 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' ] } }
利润 $$$$
但说真的......这就是我让它工作的方式。如果有人有任何问题,请告诉我。我可以试着帮忙。
图片比文字更有价值。
评论
layout-v21
'src/main/res/layouts/content'
'src/main/res/layouts/content/layout'
我使用适用于 Android 的 Android 文件分组插件 Studio.It 它并不真正允许您创建子文件夹,但它可以显示您的文件和资源,因为它们位于不同的文件夹中。这正是我想要的。
您可以通过以下方式安装“Android文件分组”插件
窗户:
Android Studio -> 文件 -> 设置 -> 插件。
苹果:
Android Studio -> Android Studio 选项卡(左上角) -> 首选项 -> 插件 ->安装 JetBrains 插件..
对于 Mac,我能够对其进行测试,但无法搜索插件。所以我从这里下载了插件,并使用了上述设置中的选项。Install plugin from disk
评论
小问题
我能够通过遵循这个问题的最高答案来实现子文件夹。
但是,随着项目规模的扩大,您将拥有许多子文件夹:
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
}
将此方法粘贴到块的外部。android {...}
app/build.gradle
如何使用
对于这样的结构:
<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 .)
R.layout.admin_home
array.push("src/main/res");
def res="src/main/res";
array.push(res);
// uncomment for debugging
src/main/res/layouts/<your_layout_files>
@eski 的顶级答案很好,但代码使用起来并不优雅,所以我在 gradle 中编写了一个时髦的脚本供一般使用。它适用于所有构建类型和产品风格,不仅可以用于布局,还可以为任何其他资源类型(如可绘制对象)添加子文件夹。这是代码(把它放在项目级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]
}
在实践中如何做?
例如,我想创建名为 的子文件夹,在变量中添加一个任意名称的字符串,例如 ,则布局 xml 文件应该放在 中。activity
layout
resDirs
layouts
res\layouts\activity\layout\xxx.xml
如果我想创建名为 的子文件夹,请在变量中添加一个任意名称的字符串,例如 ,则应将可绘制的 xml 文件放入 中。selectors
drawable
resDirs
drawables
res\drawables\selectors\drawable\xxx.xml
文件夹名称(如 和 )在变量中定义,它可以是任何字符串。
您创建的所有子文件夹(例如 或)都被视为与文件夹相同。所以在文件夹中,我们必须另外创建文件夹并将xml文件放在文件夹中,之后gradle可以正常将xml文件识别为可绘制文件。layouts
drawables
resDirs
activity
selectors
res
selectors
drawable
drawable
评论
我这样做的一种方法是在与项目中的实际 res 文件夹相同的级别创建一个单独的 res 文件夹,然后您可以在您的应用程序 build.gradle 中使用它
android {
//other stuff
sourceSets {
main.res.srcDirs = ['src/main/res', file('src/main/layouts').listFiles()]
}
}
然后,您的新 Res 文件夹的每个子文件夹都可以是与每个特定屏幕或应用程序中的某些内容相关的内容,并且每个文件夹都有自己的//等,使事情井井有条,您不必像其他一些答案那样手动更新 gradle 文件(只需在每次添加新的资源文件夹时同步您的 gradle,以便它知道它, 并确保在添加 XML 文件之前添加相关的子文件夹)。layout
drawable
values
现在,我们可以轻松使用名为“Android文件分组”的JetBrains插件"
查看此链接
评论
Android Studio
- 第 1 步:右键单击布局 - 在资源管理器中显示
- 步骤2:打开布局文件夹并直接创建子文件夹:layout_1,layout_2...
- 步骤3:打开layout_1创建文件夹布局(注意:必填名称为layout),打开layout_2文件夹创建layout子目录(注意:必填名称为layout)...
- 步骤 4:将 xml 文件复制到 layout_1 和 layout_2 中的布局子目录中
- 第 5 步:在 buid.grade(模块应用)中运行代码并立即点击同步:
sourceSets {
main {
res.srcDirs =
[
'src / main / res / layout / layout_1'
'src / main / res / layout / layout_2',
'src / main / res'
]
}
}
- 第 6 步:总结:上述所有步骤仅有助于聚类文件夹并在“项目”模式下显示,而“android”模式将正常显示。
- 因此,我认为命名前缀可能与聚类文件夹一样有效。
评论
Project
Android
如果您在批准的答案中使用了该方法,并且想要对其进行一些改进,请像这样更改 gradle 设置:
sourceSets {
main {
res.srcDirs = [
file("src/main/res/layouts/").listFiles(),
"src/main/res/layouts",
"src/main/res"
]
}
}
因此,如果您添加更多文件夹和布局,则无需返回此处并附加一长串源文件夹,让 gradle 为您获取所有文件夹。
评论
热门答案有几个缺点:您必须添加新的布局路径,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/。为了创建子文件夹,您应该使用以下菜单:新建>文件夹>分辨率文件夹。
更新
几周后,我发现 Android Studio 没有注意到资源的变化。因此,出现了一些奇怪的错误。例如,布局继续显示旧的尺寸、边距。有时 AS 找不到新的 XML 文件(尤其是在运行时)。有时它会混合 s(对另一个 XML 文件的引用)。通常需要按 或 。读取在 Android Studio 中更改 xml 布局文件后需要重新构建。view id
Build > Clean Project
Build > Rebuild Project
评论
res
不能有子目录(很容易),但你可以有其他资源文件夹。惊讶的是没有人提到它,但要保留默认的资源文件夹,并添加更多:
sourceSets {
main.res.srcDirs += ['src/main/java/XYZ/ABC']
}
在一个模块中,要组合 flavors、flavor 资源(布局、值)和 flavor 资源资源,主要要记住两件事:
在 for flavor 中添加资源目录时,请记住,在其他模块中,甚至在同一模块中,也会添加资源目录。因此,使用附加分配 () 的重要性,以免用新分配覆盖所有现有资源。
res.srcDirs
src/main/res
+=
声明为数组元素的路径是包含资源类型的路径,即资源类型是 res 文件夹通常包含的所有子目录,例如颜色、可绘制对象、布局、值等。可以更改 res 文件夹的名称。
例如,使用路径,但要注意实践层次结构必须具有子目录:"src/flavor/res/values/strings-ES"
values
├── module
├── flavor
├── res
├── values
├── strings-ES
├── values
├── strings.xml
├── strings.xml
该框架按类型精确识别资源,这就是为什么通常已知的子目录不能省略的原因。
另请记住,特定实例中的所有文件都将形成一个联合,因此资源无法复制。反过来,在 flavor 中形成文件的这个联合在模块的 main 之前具有更高的优先级。strings.xml
flavor {
res.srcDirs += [
"src/flavor/res/values/strings-ES"
]
}
将目录视为包含资源类型的 custom-res。strings-ES
GL型
评论