¿Puede la carpeta de diseño de Android contener subcarpetas?




9 Answers

La respuesta es no.

Me gustaría llamar su atención hacia este libro Pro Android 2 que dice:

También vale la pena señalar algunas limitaciones con respecto a los recursos. Primero, Android solo admite una lista lineal de archivos dentro de las carpetas predefinidas bajo resolución. Por ejemplo, no admite carpetas anidadas en la carpeta de diseño (o en las otras carpetas en resolución).

En segundo lugar, hay algunas similitudes entre la carpeta de activos y la carpeta sin formato en res. Ambas carpetas pueden contener archivos en bruto, pero los archivos en bruto se consideran recursos y los archivos en activos no lo son.

Tenga en cuenta que debido a que el contenido de la carpeta de activos no se considera un recurso, puede colocar una jerarquía arbitraria de carpetas y archivos dentro de ella.

android android-layout

En este momento, estoy almacenando cada archivo de diseño xml dentro de la carpeta res/layout , por lo que es factible y simple administrar proyectos pequeños, pero cuando hay un caso de proyectos grandes y pesados, entonces debe haber una jerarquía y subgrupos. carpetas necesarias dentro de la carpeta de diseño.

por ejemplo

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

De la misma manera, nos gustaría tener subcarpetas para la aplicación grande, ¿hay alguna forma de hacerlo dentro del proyecto de Android?

Soy capaz de crear subcarpetas layout-personal y layout_address dentro de la carpeta de diseño, pero cuando llegue el momento de acceder al archivo de diseño xml con R.layout ._______, en ese momento no hay ninguna ventana emergente de diseño xml dentro del menú.




No es posible, pero la carpeta de diseño está ordenada por nombre. Por lo tanto, antepongo los nombres de los archivos de diseño con los nombres de mis paquetes. Por ejemplo, para los dos paquetes "comprando" y "jugando":

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



Ahora, con Android Studio y Gradle, puede tener múltiples carpetas de recursos en su proyecto. Permitiendo organizar no solo tus archivos de diseño sino cualquier tipo de recursos.

No es exactamente una subcarpeta, pero puede separar partes de su aplicación.

La configuración es así:

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

Consulte la documentación .




Pequeño problema

Puedo lograr subcarpetas siguiendo la respuesta principal a esta pregunta.

Sin embargo, a medida que el proyecto crece, tendrá muchas subcarpetas:

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

No es un gran problema, pero:

  • No es bonito ya que la lista se hace muy larga.
  • tienes que cambiar tu app/build.gradle cada vez que agregues una nueva carpeta.

Mejora

Así que escribí un método Groovy simple para capturar todas las carpetas anidadas:

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
}

Pegue este método fuera del bloque de android {...} en su app/build.gradle .

Cómo utilizar

Para una estructura como esta:

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

Úsalo así:

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

Si tienes una estructura como esta:

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

Lo usarás así:

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

Explicación

getLayoutList() toma a relative path como argumento. La relative path es relativa a la raíz del proyecto. Entonces, cuando ingresamos "app/src/main/res/layouts/" , devolverá el nombre de todas las subcarpetas como una matriz, que será exactamente igual a:

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

Aquí está el guión con comentarios para su comprensión:

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
}

¡Espero eso ayude!




Una forma en que lo hice fue crear una carpeta de resolución independiente al mismo nivel que la carpeta de resolución real en su proyecto, luego puede usar esto en sus aplicaciones build.gradle

android {
    //other stuff

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

luego, cada subcarpeta de su nueva carpeta de resolución puede ser algo relacionado con cada pantalla en particular o algo en su aplicación, y cada carpeta tendrá su propio layout / drawable / values etc., manteniendo las cosas organizadas y no tendrá que actualizar el archivo de Gradle manualmente como algunos de estas otras respuestas requieren (solo sincronice su gradle cada vez que agregue una nueva carpeta de recursos para que lo sepa, y asegúrese de agregar las subcarpetas relevantes antes de agregar sus archivos XML).




Si está desarrollando en una caja de Linux o Mac, una solución alternativa sería crear subcarpetas que incluyan enlaces simbólicos a sus archivos de diseño. Solo usa el comando ln con -s

ln -s PATH_TO_YOUR_FILE

El problema con esto es que su carpeta de diseño aún contiene todos los archivos .xml. Pero podría seleccionarlos utilizando las subcarpetas. Es lo más cercano a lo que te gustaría tener.

Acabo de leer que esto también podría funcionar con Windows si está utilizando Vista o una versión posterior. Hay este comando mklink . Solo buscalo en google, nunca lo he usado yo mismo.

Otro problema es que, si tiene el archivo abierto e intenta abrirlo nuevamente, el complemento lanza una excepción de puntero NULL. Pero no cuelga.




La respuesta principal de @eski es buena, pero el código no es elegante de usar, así que escribí un guión maravilloso en Gradle para uso general. Se aplica a todo tipo de compilación y sabor del producto y no solo se puede usar para el diseño, también puede agregar subcarpetas para cualquier otro tipo de recursos, como dibujable. Aquí está el código (póngalo en el bloque de Android del archivo gradle a nivel de proyecto):

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

¿Cómo hacer en la práctica?

Por ejemplo, quiero crear una subcarpeta denominada activity para el layout , agregar una cadena con cualquier nombre en la variable resDirs , como los layouts , luego el archivo xml del diseño debe colocarse en res\layouts\activity\layout\xxx.xml .

Si quiero crear una subcarpeta llamada selectors para drawable , agregue una cadena con cualquier nombre en la variable resDirs como resDirs , entonces el archivo xml drawable debe colocarse en res\drawables\selectors\drawable\xxx.xml .

El nombre de la carpeta como layouts y drawables se define en la variable resDirs , puede ser cualquier cadena. Todas las subcarpetas creadas por usted, como la activity o los selectors se consideran lo mismo que la carpeta res . Por lo tanto, en la carpeta de selectors , debemos crear una carpeta drawable adicionalmente y colocar los archivos XML en una carpeta dibujable, después de que Gradle pueda reconocer los archivos XML como dibujables normalmente.




Si usa el método en la respuesta aprobada y desea mejorarlo un poco, cambie la configuración de gradle de esta manera:

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

Entonces, si agrega más carpetas y diseños, no necesita volver aquí y adjuntar una larga lista de carpetas de origen, deje que Gradle obtenga todas las carpetas para usted.




Las respuestas principales tienen varias desventajas: tiene que agregar nuevas rutas de diseño, AS coloca nuevos recursos en la carpeta res\layouts lugar de res\values .

Combinando varias respuestas escribí algo similar:

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

Hice carpetas con este artículo: http://alexzh.com/tutorials/how-to-store-layouts-in-different-folders-in-android-project/ . Para crear subcarpetas, debe usar este menú: Nuevo> Carpeta> Carpeta Res.

ACTUALIZAR

Después de un par de semanas descubrí que Android Studio no nota los cambios en los recursos . Por lo tanto, algunos errores extraños aparecen. Por ejemplo, los diseños siguen mostrando tamaños antiguos, márgenes. A veces, AS no encuentra nuevos archivos XML (especialmente durante el tiempo de ejecución). A veces se mezclan los view id (referencias a otro archivo XML). A menudo es necesario presionar Build > Clean Project o Build > Rebuild Project . Es .com/questions/32317822/… .






Related