Android Layout文件夹可以包含子文件夹吗?

时间:2011-02-08 06:58:08

标签: android android-layout

现在,我将每个xml布局文件存储在res/layout文件夹中,因此管理小项目是可行且简单的,但是当存在大型和重型项目的情况时,那么应该是布局文件夹中所需的层次结构和子文件夹。

例如

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

以同样的方式,我们希望为大型应用程序提供子文件夹,那么有没有办法在android项目中这样做?

我可以在布局文件夹中创建layout-personal和layout_address子文件夹,但是当使用R.layout ._______访问xml布局文件的时候,那时没有任何xml布局弹出 - 在菜单里面。

20 个答案:

答案 0 :(得分:449)

你可以用gradle做到这一点。我已经制作了demo project来展示如何。

诀窍是使用gradle的merge multiple resource folders能力,并设置res文件夹以及sourceSets块中的嵌套子文件夹。

怪癖是,在声明该文件夹的子资源文件夹之前,您无法声明容器资源文件夹。

以下是demo中build.gradle文件中的sourceSets块。请注意,子文件夹首先被声明。

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

nested resources picture

此外,实际资源文件的直接父级(png,xml布局等)仍然需要与specification对应。

答案 1 :(得分:231)

答案是否定的。

我想提请你注意这本书Pro Android 2

  

值得注意的还有一些   关于资源的限制。   首先,Android仅支持线性   预定义内的文件列表   res下的文件夹。例如,它   不支持嵌套文件夹   布局文件夹(或其他   res下的文件夹。

     

其次,有一些相似之处   资产文件夹和原始文件夹之间   res下的文件夹。这两个文件夹都可   包含原始文件,但包含文件   原始内部被视为资源   并且资产中的文件不是。

     注意因为内容了   资产文件夹不予考虑   资源,你可以把任意   中的文件夹和文件的层次结构   它

答案 2 :(得分:75)

我只是想为有困难的人添加eskis的精彩答案。 (注意:这只会起作用,看起来像'项目'视图中的单独目录,不幸的是不是'android'视图。)

使用以下测试。 BuildToolsVersion = 23.0.0 gradle 1.2.3& 1.3.0

这就是我使用已经建成的项目的方法。

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

  11. 但是说真的......这就是我开始工作的方式。如果有人有任何问题,请告诉我。我可以尝试提供帮助。

    图片不仅仅是文字。

    Directory Structure

答案 3 :(得分:52)

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

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

答案 4 :(得分:19)

我为Android Studio使用Android File Grouping插件。它实际上不允许您创建子文件夹,但它可以显示您的文件和资源,因为它们位于不同的文件夹中。这正是我想要的。

您可以通过

安装“Android文件分组”插件

Windows:

  

Android Studio - >档案 - >设置 - >插件。

的Mac:

  

Android Studio - > Android Studio标签(左上角) - >偏好 - >插件 - >安装JetBrains插件..

对于Mac,我能够测试它并且无法搜索插件。所以我从here下载了该插件,并使用了上述设置中的Install plugin from disk选项。

答案 5 :(得分:18)

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

它不完全是一个子文件夹,但可以部分应用程序。

配置如下:

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

检查documentation

答案 6 :(得分:16)

我认为这个问题最优雅的解决方案(假设不允许使用子文件夹)是在文件名前加上你将它放在里面的文件夹的名称。例如,如果您有一堆Activity,Fragment或只是名为“places”的一般视图的布局,那么您应该只使用places_my_layout_name作为前缀。至少这解决了以在IDE中更容易找到的方式组织它们的问题。这不是最棒的解决方案,但它总比没有好。

答案 7 :(得分:15)

小问题

我可以按照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
}

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

希望它有所帮助!

答案 8 :(得分:10)

现在我们可以轻松使用名为“ Android文件分组”的JetBrains插件

查看此链接

Android File Grouping

enter image description here

答案 9 :(得分:5)

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

android {
    //other stuff

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

example folder structure

然后,新res文件夹的每个子文件夹都可以与您的应用中的每个特定屏幕相关联,并且每个文件夹都有自己的layout / drawable / values等保持井井有条,你不必像其他一些答案那样手动更新gradle文件(每次添加新的资源文件夹时都要同步你的gradle,以便它知道它,并确保在添加你之前添加相关的子文件夹xml文件)。

答案 10 :(得分:4)

检查将文件夹层次结构转换为单个文件夹的Bash Flatten Folder script

答案 11 :(得分:3)

如果您正在开发Linux或Mac机箱,那么解决方法就是创建包含指向布局文件的符号链接的子文件夹。只需将ln命令与-s

一起使用即可
  

ln -s PATH_TO_YOUR_FILE

问题是,您的Layout文件夹仍包含所有.xml文件。但您可以使用子文件夹选择它们。这是你最想要的东西。

我刚读过,如果您使用的是Vista或更高版本,这也适用于Windows。有mklink命令。只是google它,从来没有用过它。

另一个问题是,如果您打开了文件并尝试再次打开它,则插件会抛出NULL指针异常。但它并没有挂断。

答案 12 :(得分:3)

@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]
}

如何在实践中做到?

例如,我想为activity创建名为layout的子文件夹,在resDirs变量中添加任意名称的字符串,例如layouts,然后添加布局xml文件应该放在res\layouts\activity\layout\xxx.xml

如果我想为selectors创建名为drawable的子文件夹,请在resDirs变量中添加任意名称的字符串,例如drawables,那么可绘制的xml文件应为放入res\drawables\selectors\drawable\xxx.xml

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

答案 13 :(得分:3)

虽然可以使用多个资源集的所有提议,但问题是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/提交了一个补丁,试图帮助解决问题。

答案 14 :(得分:2)

如果您在批准的答案中使用该方法,并且想对它进行一点改进,则可以像下面这样更改gradle设置:

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

因此,如果您添加更多文件夹和布局,则无需返回此处并添加一长串源文件夹,让gradle为您获取所有文件夹。

答案 15 :(得分:1)

  • 第1步:右键点击布局 - 在资源管理器中显示
  • 步骤2:打开布局文件夹并直接创建子文件夹:layout_1,layout_2 ...
  • 第3步:打开layout_1创建文件夹布局(注意:必填名称是布局),打开layout_2文件夹创建布局子目录(注意:必填名称是布局)......
  • 步骤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步:摘要:上述所有步骤仅有助于群集文件夹并显示在“项目”中。模式,而&#39; android&#39;模式将正常显示。
  • 所以我画的可能是命名前缀和群集文件夹一样有效。

答案 16 :(得分:0)

嗯,简短的回答是否定的。但你绝对可以拥有多个res个文件夹。我认为,这与layout文件夹的子文件夹一样接近。 Here's你是怎么做到的。

答案 17 :(得分:0)

最常见的答案有几个缺点:您必须添加新的布局路径,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> Folder> Res Folder。

更新

几周后,我发现Android Studio没有注意到资源变化。因此,出现了一些奇怪的错误。例如,布局继续显示旧尺寸,边距。有时,AS找不到新的XML文件(尤其是在运行时)。有时,它会混合view id(对另一个XML文件的引用)。通常需要按Build > Clean ProjectBuild > Rebuild Project。阅读Rebuild required after changing xml layout files in Android Studio

答案 18 :(得分:0)

不能轻松拥有子目录,但是可以拥有其他个资源文件夹。没有人惊讶,没有提到它,而是保留默认资源文件夹,并添加更多内容:

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

答案 19 :(得分:0)

在一个模块中,要具有风味,风味资源(布局,值)和风味资源资源的组合,需要牢记的两件事是:

  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