Can the Android Layout folder contain subfolders?

2018-12-31 05:46发布

Right now, I'm storing every xml layout file inside the res/layout folder, so it is feasible and simple to manage small projects, but when there is a case of large and heavy projects, then there should be a hierarchy and sub-folders needed inside the layout folder.

for e.g.

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

Like the same way, we would like to have sub-folders for the large application, so is there any way to do so inside the android project?

I am able to create layout-personal and layout_address sub-folders inside the layout folder, but when the time comes to access the xml layout file using R.layout._______ , at that time there is no any xml layout pop-up inside the menu.

18条回答
牵手、夕阳
2楼-- · 2018-12-31 05:53

If you are developing on a linux or a mac box, a workaround would be, to create subfolders which include symbolic links to your layoutfiles. Just use the ln command with -s

ln -s PATH_TO_YOUR_FILE

The Problem with this is, that your Layout folder still contains all the .xml files. But you could although select them by using the sub-folders. It's the closest thing, to what you would like to have.

I just read, that this might work with Windows, too if you are using Vista or later. There is this mklink command. Just google it, have never used it myself.

Another problem is, if you have the file opened and try to open it again out the plugin throws a NULL Pointer Exception. But it does not hang up.

查看更多
裙下三千臣
3楼-- · 2018-12-31 05:59

Small Problem

I am able to achieve subfolders by following the top answer to this question.

However, as the project grows bigger, you will have many sub-folders:

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

Not a big problem, but:

  • it's not pretty as the list become very long.
  • you have to change your app/build.gradle everytime you add a new folder.

Improvement

So I wrote a simple Groovy method to grab all nested folders:

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
}

Paste this method outside of the android {...} block in your app/build.gradle.


How to use

For a structure like this:

<project root>
├── app <---------- TAKE NOTE
├── build
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle

Use it like this:

android {
    sourceSets {
        main {
            res.srcDirs = getLayoutList("app/src/main/res/layouts/")
        }
    }
}

If you have a structure like this:

<project root>
├── my_special_app_name <---------- TAKE NOTE
├── build
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle

You will use it like this:

android {
    sourceSets {
        main {
            res.srcDirs = getLayoutList("my_special_app_name/src/main/res/layouts/")
        }
    }
}

Explanation

getLayoutList() takes a relative path as an argument. The relative path is relative to the root of the project. So when we input "app/src/main/res/layouts/", it will return all the subfolders' name as an array, which will be exactly the same as:

            [
                    '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'
            ]

Here's the script with comments for understanding:

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
}

Hope it helps!

查看更多
初与友歌
4楼-- · 2018-12-31 06:03

I just wanted to add onto eskis' fantastic answer for people having trouble. (Note: This will only work and look like separate directories inside the 'project' view, not the 'android' view unfortunately.)

Tested with the following. BuildToolsVersion = 23.0.0 gradle 1.2.3 & 1.3.0

This is how I got mine to work with an already built project.

  1. Copy all of the XML files out of your layout directory, and put them into a directory on the desktop or something for backup.
  2. Delete the entire layout directory (Make sure you backed everything up from step 1!!!)
  3. Right click the res directory and select new > directory.
  4. Name this new directory "layouts". (This can be whatever you want, but it will not be a 'fragment' directory or 'activity' directory, that comes later).
  5. Right click the new "layouts" directory and select new > directory. (This will be the name of the type of XML files you will have in it, for example, 'fragments' and 'activities').
  6. Right click the 'fragment' or 'activities' directory (Note: this doesn't have to be 'fragment' or 'activities' that's just what i'm using as an example) and select new > directory once again and name this directory "layout". (Note: This MUST be named 'layout'!!! very important).
  7. Put the XML files you want inside the new 'layout' directory from the backup you made on your desktop.
  8. Repeat steps 5 - 7 for as many custom directories as you desire.
  9. Once this is complete, go into your modules gradle.build file and create a sourceSets definition like this...(Make sure 'src/main/res/layouts' & 'src/main/res' are always the bottom two!!!! Like I am showing below).

    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

查看更多
柔情千种
5楼-- · 2018-12-31 06:03

A way i did it was to create a separate res folder at the same level as the actual res folder in your project, then you can use this in your apps build.gradle

android {
    //other stuff

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

example folder structure

then each subfolder of your new res folder can be something relating to each particular screen or something in your app, and each folder will have their own layout / drawable / values etc keeping things organised and you dont have to update the gradle file manually like some of these other answers require (Just sync your gradle each time you add a new resource folder so it knows about it, and make sure to add the relevant subfolders before adding your xml files).

查看更多
荒废的爱情
6楼-- · 2018-12-31 06:05

I use Android File Grouping plugin for Android Studio.It doesn't really allows you to create sub-folders, but it can DISPLAY your files and resources AS they are in different folders. And this is exactly what I wanted.

You can install "Android File Grouping" plugin by

Windows:

Android Studio -> File -> Settings -> Plugins.

Mac:

Android Studio -> Android Studio Tab (Top Left) -> Preferences -> Plugins -> Install JetBrains Plugin..

For Mac, I was able to test it and was not able to search for the plugin. So I downloaded the plugin from here and used the Install plugin from disk option from the above setting.

查看更多
宁负流年不负卿
7楼-- · 2018-12-31 06:05

Top answers have several disadvantages: you have to add new layout paths, AS places new resources to res\layouts folder instead of res\values.

Combining several answers I wrote similar:

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

I made folders with this article: http://alexzh.com/tutorials/how-to-store-layouts-in-different-folders-in-android-project/. In order to create subfolders you should use this menu: New > Folder > Res Folder.

UPDATE

After a couple of weeks I found that changes in resources are not noticed by Android Studio. So, some weird bugs appear. For instance, layouts continue to show old sizes, margins. Sometimes AS doesn't find new XML-files (especially during run-time). Sometimes it mixes view ids (references to another XML-file). It's often required to press Build > Clean Project or Build > Rebuild Project. Read Rebuild required after changing xml layout files in Android Studio.

查看更多
登录 后发表回答