Android布局文件夹可以包含子文件夹吗?

现在,我在'res/layout'文件夹内存储每个XML布局文件,因此管理小型项目是可行和简单的,但当有大型和繁重的项目的情况下,那么应该有一个层次结构和子文件夹内需要的布局文件夹。

如。

layout
-- layout_personal
-- personal_detail.xml
-- personal_other.xml
--layout_address
-- address1.xml
-- address2.xml

同样,我们希望大型应用程序有子文件夹,那么在Android项目中有办法做到这一点吗?

我能够在布局文件夹内创建layout-personal和layout_address子文件夹,但当需要使用R.layout访问XML布局文件时。_______,当时在菜单中没有任何XML布局弹出。

200805 次浏览

答案是否定的。

我想提请您注意这本书Pro Android 2,其中写道:

也有一些值得注意 资源方面的限制。 首先,Android只支持线性 预定义文件中的文件列表 例如,it .文件夹 不支持下的嵌套文件夹 布局文件夹(或其他

其次,有一些相似之处 在资产文件夹和原始文件之间 两个文件夹都可以 包含原始文件,但文件 在raw中被认为是资源 而资产中的文件则不是

请注意,因为 不考虑资产文件夹 资源中,可以放一个任意 内的文件夹和文件的层次结构 它。< / p >

如果你是在linux或mac上开发,一种变通方法是,创建包含符号链接到布局文件的子文件夹。只需使用ln命令和-s

ln -s PATH_TO_YOUR_FILE

问题是,你的布局文件夹仍然包含所有的.xml文件。但是你可以通过使用子文件夹来选择它们。这是最接近你想要的东西。

我刚读到,如果你使用的是Vista或更高版本,这可能也适用于Windows。这里有一个mklink命令。只是谷歌,我从来没用过。

另一个问题是,如果你已经打开了文件,并试图再次打开它,插件抛出一个空指针异常。但它并没有挂断。

不可能,但是布局文件夹是按名称排序的。因此,我在布局文件名前加上包名。例如,对于“购买”和“玩”两个包:

buying_bought_tracks.xml
buying_buy_tracks.xml
playing_edit_playlist.xml
playing_play_playlist.xml
playing_show_playlists.xml

我认为这个问题最优雅的解决方案(考虑到子文件夹是不允许的)是在文件名前面加上文件夹的名称。例如,如果你有一堆布局的活动,片段,或只是一般的视图称为“地方”,那么你应该用places_my_layout_name它。至少这解决了以一种在IDE中更容易找到它们的方式组织它们的问题。这不是最好的解决方案,但总比什么都没有强。

现在有了Android Studio和Gradle,你可以在你的项目中有多个资源文件夹。允许组织不仅你的布局文件,但任何类型的资源。

它不是一个确切的子文件夹,但可以分离应用程序的部分。

配置如下:

sourceSets {
main {
res.srcDirs = ['src/main/res', 'src/main/res2']
}
}

检查文档

你可以用gradle做到这一点。我已经做了一个演示项目显示如何。

诀窍是使用gradle的能力合并多个资源文件夹,并设置res文件夹以及sourceSets块中的嵌套子文件夹。

奇怪的是,在声明容器资源文件夹的子资源文件夹之前,您不能声明该文件夹。

下面是构建中的sourceSets块。演示中的Gradle文件。注意,先声明子文件夹。

sourceSets {
main {
res.srcDirs =
[
'src/main/res/layouts/layouts_category2',
'src/main/res/layouts',
'src/main/res'
]
}
}

嵌套资源图片

同样,你的实际资源文件(png, xml布局等)的直接父文件仍然需要与规范对应。

选中将文件夹层次结构转换为单个文件夹的Bash Flatten Folder脚本

简而言之,答案是否定的。但是你绝对可以有多个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 < / p >

这就是我如何让我的工作与一个已经建立的项目。

  1. 从布局目录中复制所有XML文件,并将它们放入桌面或其他目录中进行备份。
  2. 删除整个布局目录(确保从第1步开始备份所有内容!!)
  3. 右键单击res目录并选择新的>目录。
  4. 命名这个新目录为layouts。(这可以是任何你想要的,但它不会是一个'片段'目录或'活动'目录,这是后面的)。
  5. 右键单击新的“layouts”目录并选择新的>目录。(这将是您将在其中的XML文件类型的名称,例如“片段”和“活动”)。
  6. 右键单击“fragment”或“activities”目录(注意:这并不一定是“fragment”或“activities”,这只是我使用的例子),并再次选择新的>目录,并将此目录命名为“layout”。(注意:这个必须命名为'layout'!!非常重要)。
  7. 把你想要的XML文件放到桌面上备份的新“布局”目录中。
  8. 重复步骤5 - 7为您想要的任意多个自定义目录。
  9. 一旦完成,进入你的模块gradle。然后创建一个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'
    ]
    }
    }
    
  10. Profit $$$$

But seriously.. this is how I got it to work. Let me know if anyone has any questions.. I can try to help.

Pictures are worth more than words.

Directory Structure

我使用Android文件分组插件的Android工作室。它不允许你创建子文件夹,但是它可以显示你的文件和资源,因为它们在不同的文件夹中。这正是我想要的。

你可以安装“Android文件分组”插件通过

窗口:

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
}

将这个方法粘贴到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
}

希望能有所帮助!

@eski给出的最上面的答案很好,但是代码使用起来并不优雅,所以我在gradle中编写了一个groovy脚本以供一般使用。它适用于所有构建类型和产品风格,不仅可以用于布局,还可以为任何其他资源类型(如drawable)添加子文件夹。下面是代码(放在项目级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中。

文件夹名称如layoutsdrawables是在resDirs变量中定义的,它可以是任何字符串。 您创建的所有子文件夹,如activityselectors,均视为与res文件夹相同。所以在selectors文件夹中,我们必须另外创建drawable文件夹,并将xml文件放在drawable文件夹中,之后gradle才能正常识别xml文件是可绘制的

我这样做的一种方式是在你的项目中创建一个与实际res文件夹相同级别的单独的res文件夹,然后你可以在你的应用程序build.gradle中使用这个

android {
//other stuff


sourceSets {
main.res.srcDirs = ['src/main/res', file('src/main/layouts').listFiles()]
}
}

example folder structure

然后每个新res文件夹的子文件夹可以一些有关每个特定屏幕或一些在你的应用程序,和每个文件夹都有自己的# EYZ0 / # EYZ1 / # EYZ2等保持事物的组织和你不必须手动更新gradle文件和其他一些答案要求(同步你gradle每次添加一个新的资源文件夹,所以它知道它,并确保添加相关的子文件夹之前添加xml文件)。

现在我们可以很容易地用JetBrains插件“Android文件分组

看看这个链接

Android文件分组

enter image description here

  • 第一步:在资源管理器中右键单击布局-显示
  • 步骤2:打开布局文件夹并直接创建子文件夹:layout_1, layout_2…
  • 步骤3:打开layout_1创建文件夹布局(注意:必选名称为布局),打开layout_2文件夹创建文件夹布局子目录(注意:必选名称为布局)…
  • 步骤4:将xml文件复制到layout_1和layout_2的布局子目录中
  • 步骤5:运行build中的代码。Grade(模块应用),现在点击同步:

sourceSets {
main {
res.srcDirs =
[
'src / main / res / layout / layout_1'
'src / main / res / layout / layout_2',
'src / main / res'
]
}
}
  • 第6步:总结:以上所有步骤将只帮助集群文件夹和显示在“项目”模式,而“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/。为了创建子文件夹,你应该使用这个菜单:新建>文件夹> Res文件夹。

更新

几周后,我发现Android Studio不会注意到资源的变化。于是,一些奇怪的虫子出现了。例如,布局仍然显示旧的尺寸和页边距。有时AS找不到新的xml文件(特别是在运行时)。有时它混合使用view ids(对另一个xml文件的引用)。通常需要按Build > Clean ProjectBuild > Rebuild Project。# EYZ4阅读。

不能有子目录(很容易),但可以有额外的资源文件夹。很惊讶居然没有人提到它,但保持默认资源文件夹,并添加更多:

    sourceSets {
main.res.srcDirs += ['src/main/java/XYZ/ABC']
}

在一个模块中,要拥有风味、风味资源(布局、值)和风味资源的组合,主要要记住两件事:

  1. 当在res.srcDirs中添加资源目录时,请注意在其他模块中,甚至在同一模块的src/main/res中,也会添加资源目录。因此,使用附加赋值(+=)非常重要,这样就不会用新赋值覆盖所有现有资源。

  2. 声明为数组元素的路径是包含资源类型的路径,即资源类型为res文件夹所包含的所有子目录,如颜色,可绘制,布局,值等。res文件夹的名称可以更改。

一个例子是使用路径"src/flavor/res/values/strings-ES",但是观察实践层次结构必须有子目录values:

├── module
├── flavor
├── res
├── values
├── strings-ES
├── values
├── strings.xml
├── strings.xml
 

该框架精确地根据类型识别资源,这就是为什么通常已知的子目录不能被省略。

还要记住,flavor中的所有strings.xml文件将形成一个联合,这样资源就不能被复制。反过来,这个组成该类型文件的联合在模块的主文件之前具有更高的优先级。

flavor {
res.srcDirs += [
"src/flavor/res/values/strings-ES"
]
}

strings-ES目录视为包含资源类型的自定义资源。

GL