Может ли папка Android Layout содержать подпапки?

В настоящий момент я сохраняю каждый файл макета xml внутри папки макета, поэтому вполне возможно и просто управлять небольшими проектами, но когда есть случай с большими и тяжелыми проектами, тогда должна быть иерархия и подпапки необходимо в папке макета.

например.

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

Подобным образом мы хотели бы иметь подпапки для большого приложения, так есть ли способ сделать это внутри проекта Android?

Я могу создать подпапки layout-personal и layout_address внутри папки макета, но когда придет время получить доступ к файлу макета xml, используя R.layout. _, в то время там во всплывающем меню xml нет всплывающего меню.

410
задан Paresh Mayani 08 февр. '11 в 9:58
источник поделиться
15 ответов

Вы можете сделать это с помощью gradle. Я сделал демонстрационный проект показывающий, как.

Фокус в том, чтобы использовать gradle способность объединить несколько папок ресурсов и установить папку res, а также вложенные подпапки в sourceSets.

Причуда заключается в том, что вы не можете объявить папку ресурса контейнера, прежде чем объявлять папки дочерних ресурсов папки.

Ниже приведен блок sourceSets из файла build.gradle из демонстрации. Обратите внимание, что вложенные папки объявлены первыми.

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

nested resources picture

Кроме того, прямой родительский файл ваших фактических файлов ресурсов (pngs, xml layouts и т.д.) все равно должен соответствовать спецификации .

370
ответ дан eski 15 марта '14 в 19:26
источник поделиться

Ответ - нет.

Я хотел бы обратить ваше внимание на эту книгу Pro Android 2, которая гласит:

Также стоит отметить несколько ограничения в отношении ресурсов. Во-первых, Android поддерживает только линейную список файлов в пределах предопределенного папки под res. Например, это не поддерживает вложенные папки в папке макета (или другой папки под res).

Во-вторых, есть некоторые общие черты между папкой с ресурсами и сырой папка под res. Обе папки могут содержат необработанные файлы, но файлы в рамках сырья рассматриваются ресурсы и файлы внутри активов не являются.

Обратите внимание, что поскольку содержимое Активы не учитываются ресурсов, вы можете поставить произвольный иерархия папок и файлов вон.

219
ответ дан 100rabh 08 февр. '11 в 10:17
источник поделиться

Я просто хотел добавить фантастический ответ eskis для людей, испытывающих проблемы. (Примечание. Это будет работать и будет выглядеть как отдельные каталоги внутри "проекта", а не "андроида" ).

Протестировано следующим образом. BuildToolsVersion = 23.0.0 gradle 1.2.3 и 1.3.0

Вот как я получил свою работу с уже построенным проектом.

  • Скопируйте все XML файлы из своего каталога макета и поместите их в каталог на рабочем столе или что-то для резервного копирования.
  • Удалить весь каталог макета (убедитесь, что вы сделали все с первого шага!!!)
  • Щелкните правой кнопкой мыши каталог res и выберите новый каталог > .
  • Назовите этот новый каталог "layouts". (Это может быть то, что вы хотите, но это не будет каталог "фрагмент" или "активность", который будет представлен позже).
  • Щелкните правой кнопкой мыши новый каталог "layouts" и выберите новый > каталог. (Это будет имя типа файлов XML, которые вы будете иметь в нем, например, "фрагменты" и "действия" ).
  • Щелкните правой кнопкой мыши по каталогу "фрагмент" или "деятельность" (обратите внимание: это не обязательно "фрагмент" или "действия", которые я использую только в качестве примера) и снова выберите новую > директорию назовите этот каталог "layout". (Примечание: Это ДОЛЖНО быть названо "макет"!!! очень важно).
  • Поместите XML файлы в новый каталог "layout" из резервной копии, сделанной на вашем рабочем столе.
  • Повторите шаги 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'
                    ]
        }
    }
    
  • Прибыль $$$$

Но серьезно.. вот как я заработал. Дайте мне знать, есть ли у кого-нибудь вопросы. Я могу попытаться помочь.

Картинки стоят больше, чем слова.

Структура каталога

63
ответ дан hitch.united 25 авг. '15 в 6:12
источник поделиться

Невозможно, но папка макета сортируется по имени. Итак, я добавляю имена файлов макетов с именами пакетов. Например. для двух пакетов "покупка" и "игра":

buying_bought_tracks.xml
buying_buy_tracks.xml
playing_edit_playlist.xml
playing_play_playlist.xml
playing_show_playlists.xml
48
ответ дан delformo 22 окт. '11 в 2:19
источник поделиться

Теперь с Android Studio и Gradle вы можете иметь несколько папок ресурсов в своем проекте. Позволяет организовать не только ваши файлы макета, но и любые ресурсы.

Это не совсем подпапка, но может разделять части вашего приложения.

Конфигурация выглядит так:

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

Проверьте документацию.

18
ответ дан Androiderson 04 февр. '14 в 16:38
источник поделиться

Я использую Android File Grouping для Android Studio. Он не позволяет создавать подпапки, но он может отображать ваши файлы и ресурсы. Они находятся в разных папках. И это именно то, что я хотел.

Вы можете установить плагин "Android File Grouping" на

Windows:

Android Studio → Файл → Настройки → Плагины.

Mac:

Android Studio → вкладка Android Studio (вверху слева) → Настройки → Плагины → Установка плагина JetBrains..

Для Mac я смог проверить его и не смог найти плагин. Поэтому я загрузил плагин из здесь и использовал параметр Install plugin from disk из приведенной выше настройки.

17
ответ дан Sharpe 28 авг. '15 в 9:59
источник поделиться

Я думаю, что наиболее изящное решение этой проблемы (учитывая, что вложенные папки не разрешены) заключается в том, чтобы добавить имена файлов с именем папки, в которую вы разместили ее внутри. Например, если у вас есть куча макетов для Activity, Fragment или просто общий вид, называемый "местами", вы должны просто добавить его с помощью place_my_layout_name. По крайней мере, это решает проблему их организации таким образом, что их легче найти в среде IDE. Это не самое удивительное решение, но это лучше, чем ничего.

15
ответ дан botbot 05 июня '12 в 5:41
источник поделиться

Маленькая проблема

Я могу получить подпапки, следуя верхнему ответу на этот вопрос.

Однако, по мере роста проекта, у вас будет много подпапок:

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

Здесь script с комментариями для понимания:

def getLayoutList(path) {
    // let 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
}

Надеюсь, что это поможет!

11
ответ дан dragon who spits fire 29 апр. '16 в 9:40
источник поделиться

Отметьте Bash Сгладить папку script, которая преобразует иерархию папок в одну папку

4
ответ дан Sneg 14 мая '14 в 11:36
источник поделиться

Теперь мы можем легко сделать с плагином JetBrains под названием " Группировка файлов Android"

проверить эту ссылку

Группировка Android файлов

введите описание изображения здесь

3
ответ дан Bharath Kumar Bachina 04 нояб. '17 в 14:48
источник поделиться

Если вы разрабатываете Linux или Mac-поле, обходным решением будет создание подпапок, которые содержат символические ссылки на ваши макеты. Просто используйте команду ln с -s

ln -s PATH_TO_YOUR_FILE

Проблема заключается в том, что ваша папка Layout все еще содержит все XML файлы. Но вы можете выбрать их, используя подпапки. Это самое близкое, к тому, что вы хотели бы иметь.

Я просто прочитал, что это может работать и с Windows, если вы используете Vista или позже. Существует команда mklink. Просто Google, он никогда не использовал его сам.

Другая проблема заключается в том, что если вы открыли файл и попытаетесь открыть его снова, плагин выдает исключение NULL Pointer Exception. Но он не вешает трубку.

3
ответ дан Darokthar 08 февр. '11 в 10:42
источник поделиться

Верхний ответ от @eski хорош, но код не изящный, поэтому я написал groovy script в gradle для общего использования. Он применяется ко всем типам сборки и вкусу продукта и не только может использоваться для макета, вы также можете добавить подпапку для любого другого типа ресурсов, например, для рисования. Вот код (поместите его в блок android на уровне проекта gradle):

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.

Имя папки, например layouts и drawables, определяется в переменной resDirs, это может быть любая строка. Вся вложенная папка, созданная вами, например activity или selectors, считается такой же, как папка res. Поэтому в папке selectors мы должны дополнительно создать папку drawable и поместить файлы xml в папку drawable, после чего gradle может распознавать файлы xml как обычно доступные.

2
ответ дан AvatarQing 18 авг. '16 в 5:48
источник поделиться

Хотя все предложения для нескольких наборов ресурсов могут работать, проблема в том, что текущая логика для подключаемого модуля 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/, чтобы попытаться помочь решить проблемы.

2
ответ дан rogerhu 02 июля '15 в 17:24
источник поделиться

Я сделал это, чтобы создать отдельную папку res на том же уровне, что и фактическая папка res в вашем проекте, тогда вы можете использовать ее в своих приложениях build.gradle

android {
    //other stuff

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

пример структуры папок

то каждая вложенная папка вашей новой папки res может быть чем-то относящимся к каждому конкретному экрану или что-то в вашем приложении, и каждая папка будет иметь свои собственные layout/drawable/values и т.д., чтобы все было организовано, и вы не должны обновить файл gradle вручную, как это требуется для некоторых из этих других ответов.

1
ответ дан Fonix 23 авг. '17 в 12:23
источник поделиться

Ну, короткий ответ - нет. Но вы определенно можете иметь несколько папок res. Это, я думаю, так же близко, как вы можете получить подпапки для папки layout. Вот как вы это делаете.

0
ответ дан sravan953 25 мая '15 в 14:54
источник поделиться

Другие вопросы по меткам