Materialdrawer: ¿Es posible utilizar el mismo objeto Drawer en diferentes actividades?

Creado en 12 jul. 2016  ·  27Comentarios  ·  Fuente: mikepenz/MaterialDrawer

Hola,

Recibo un error si intento sujetar el objeto Cajón y mostrarlo más de una vez.
¿Es posible, por consideraciones de rendimiento, crear exactamente un cajón (estático) y usarlo en otras actividades?
Me doy cuenta de que la mejor práctica sería realizar una actividad con fragmentos, pero este no es el caso.

Gracias
Un costi

question

Comentario más útil

@acosti creó una nueva versión v5.3.5 que permite esto.
https://github.com/mikepenz/MaterialDrawer/releases/tag/v5.3.5

Todos 27 comentarios

@acosti, si no puede usar una actividad con fragmentos (que definitivamente es la implementación correcta), tendrá que optar por un enfoque diferente.

Definitivamente NO hay posibilidad de que el cajón esté _estático_.

Lo que puede hacer es tener una clase de ayuda que cree el cajón para usted (con la misma lógica) y simplemente llame a este ayudante en todas sus actividades. Pero el cajón .build() tiene que ser llamado en cada una de esas actividades, de lo contrario no se agrega el cajón.

Ok, entonces mi pregunta sería:
¿Hay alguna manera de que dicha clase auxiliar cree el cajón solo una vez, pero lo construya () varias veces en diferentes etapas de la aplicación?

Lo racional se debe al hecho de que no es barato para mí crear el cajón, ya que está altamente personalizado e interactúa con varios otros componentes de la aplicación. Así que recrearlo cada vez desde cero sería suicida en términos de rendimiento.

@acosti sí, eso es posible. Puede mantener el DrawerBuilder global una vez. Y llame a build() por actividad, ya que esto iniciará el inflado de los diseños en su aplicación al final.

Ok mike, gracias. Agradezco la ayuda.

Disculpe Mike, pero no parece funcionar.

Recibo un error de tiempo de ejecución explícito:
"no debes reutilizar un constructor de DrawerBuilder" ... tengo que admitir que ese es uno de los mensajes de error más informativos. ¿Algunas ideas?

@acosti oh Me olvidé de este comportamiento porque tenía que evitar que la gente llamara a .build() varias veces (lo que haría que tuvieran varios cajones en la misma actividad)

La solución más sencilla sería mantener la información "cara" en todo el mundo y reconstruir el cajón con normalidad. Supongo que obtener los artículos es costoso para usted, así que ¿mantener esos artículos en todo el mundo?

sí, supongo que esa es la solución sensata para mi loco problema.
Si se te ocurre uno mejor para sostener todo el objeto Drawer, me encantaría saberlo.

de cualquier manera, gracias por las rápidas respuestas. tu biblioteca me ha ahorrado toneladas de tiempo.

@acosti , podría hacer una solicitud de extracción y agregar un método reset al DrawerBuilder que establece el campo mUsed nuevo en falso.

https://github.com/mikepenz/MaterialDrawer/blob/develop/library/src/main/java/com/mikepenz/materialdrawer/DrawerBuilder.java#L71

esto le permitiría hacer esto. Y aún evitará la reutilización de DrawerBuilder para personas que no están muy seguras de lo que están haciendo

@acosti creó una nueva versión v5.3.5 que permite esto.
https://github.com/mikepenz/MaterialDrawer/releases/tag/v5.3.5

Hola,

Intenté usar el método .reset () que proporcionó, pero tengo problemas.
Aquí está el error que recibo.

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

Lo que hice fue:

  1. Crear un DrawerBuilder
  2. Guarde DrawerBuilder como una variable estática
  3. Construya () el DrawerBuilder en la Actividad A
  4. Al cargar la Actividad B - restablecer () el DrawerBuilder
  5. Informe al DrawerBuilder de la nueva actividad: .withActivity(Activity B)
  6. Construya () el DrawerBuilder en la Actividad B

Y luego se estrelló.

@acosti Creo que esto puede estar relacionado con la reutilización de DrawerLayout :
https://github.com/mikepenz/MaterialDrawer/issues/1399#issuecomment -233190027

¿Puedes intentar llamar también a withDrawerLayout(-1) adicionalmente a withActivity

Mierda, eso fue rápido. Gracias tio, de verdad.

Desafortunadamente, el mismo resultado. Déjame pegar todo el registro aquí.

FATAL EXCEPTION: main
                                                                                               Process: com.example.agombiprototypetest.prototypetest, PID: 20689
                                                                                               java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.agombiprototypetest.prototypetest/com.example.agombiprototypetest.prototypetest.Prototypes.core.aboutUs}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
                                                                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                                                                   at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                                   at android.os.Looper.loop(Looper.java:148)
                                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)`

`Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
                                                                                                   at android.view.ViewGroup.addViewInner(ViewGroup.java:4309)
                                                                                                   at android.view.ViewGroup.addView(ViewGroup.java:4145)
                                                                                                   at android.view.ViewGroup.addView(ViewGroup.java:4117)
                                                                                                   at com.mikepenz.materialdrawer.DrawerBuilder.createContent(DrawerBuilder.java:1629)
                                                                                                   at com.mikepenz.materialdrawer.DrawerBuilder.buildView(DrawerBuilder.java:1483)
                                                                                                   at com.mikepenz.materialdrawer.DrawerBuilder.build(DrawerBuilder.java:1281)
                                                                                                   at com.example.agombiprototypetest.prototypetest.BL.Navigation.DrawerNavigationModel.BuildDrawerWithToolbar(DrawerNavigationModel.java:119)
                                                                                                   at com.example.agombiprototypetest.prototypetest.BL.Navigation.DrawerNavigationModel.injectView(DrawerNavigationModel.java:96)
                                                                                                   at com.example.agombiprototypetest.prototypetest.BL.Models.AgombiNavActivity.onCreate(AgombiNavActivity.java:37)
                                                                                                   at android.app.Activity.performCreate(Activity.java:6237)
                                                                                                   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                                                                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                                                                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                                                                                                   at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                                   at android.os.Looper.loop(Looper.java:148) 
                                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                                                                   at java.lang.reflect.Method.invoke(Native Method) 

Estoy seguro.

Este es el proceso:

  1. La actividad A necesita un cajón
  2. DrawerBuilder prepara el cajón
  3. DrawerBuilder se vincula a la Actividad A a través de .withActivity(Activity A) y también restablece el diseño a través de .withDrawerLayout(-1)
  4. DrawerBuilder es built()
  5. La actividad B necesita un cajón
  6. DrawerBuilder obtiene reset()
  7. DrawerBuilder se vincula a la Actividad B a través de withActivity(Activity B) y también restablece el diseño a través de .withDrawerLayout(-1)
  8. DrawerBuilder cuesta built

¿Podría enviar estos pasos como muestra para que pueda depurarlos? Gracias

hmm eso va a ser un poco difícil. déjame intentar hacer algo para que lo veas.

Ok, esto será complicado. Por favor, tengan paciencia conmigo y con gusto responderé a cualquier pregunta lo antes posible.

Cada actividad que contiene un cajón usa el siguiente código:

private void initDrawerForActivity(Context activityContext)
    {
        // Get the activity
        AgombiNavActivity activity = (AgombiNavActivity) activityContext;

        if (sSharedDrawer == null) {
            sSharedDrawer =generateDrawer(activityContext);
        }
        else {
            sSharedDrawer.reset();
        }

        sSharedDrawer.withActivity(activity)
                     .withDrawerLayout(-1);
    }

El código de generación de cajón de generateDrawer(activityContext) es el siguiente:

private DrawerBuilder generateDrawer(Context context) {

        // Get the menu items
        RealmResults<AgombiComponentRealm> menuItems =
                NavigationManager.getInstance().getMenu();

        List<IDrawerItem> drawerItems = new LinkedList<>();

        for (final AgombiComponentRealm menuItem : menuItems) {

        // Get the drawer item externally
            PrimaryDrawerItem item =
                    AgombiViewLoader.getInstance().initializeMenuItem(context, menuItem);
            drawerItems.add(item);
        }

       // Get the footer externally
        ViewGroup footer = AgombiViewLoader.getInstance().initializeDrawerFooter(context);

        DrawerBuilder drawerBuilder = new DrawerBuilder()
                .withTranslucentStatusBar(false)
                .withDelayDrawerClickEvent(300)
                .withDrawerItems(drawerItems)
                .withFooter(footer)
                .withFooterDivider(false);
        // TODO: turn footer to sticky (removing its divider as sticky doesn't work - attempt to solve)

        return drawerBuilder;
    }

Ahora, la actividad requiere la función de construcción. Pero no es tan sencillo.
Cada actividad de mi proyecto es responsable de su propia navegación, por lo que una actividad puede tener un cajón pero sin una barra de herramientas. O con una barra de herramientas. Así que primero tengo que comprobar esto.
A continuación se muestra el código que verifica si se requiere una barra de herramientas o no y, en consecuencia, invoca la compilación () de DrawerBuilder.

public void injectView(ViewGroup activityLayout) {

        Drawer projectedDrawer = null;
        Toolbar potentialToolbar = getToolbar();
        // Check whether a toolbar is required. If so, build a combined Drawer + Toolbar
        if (potentialToolbar == null)
        {
            projectedDrawer = sSharedDrawer.build();
        }
        else
        {
            projectedDrawer = BuildDrawerWithToolbar(sSharedDrawer, activityLayout, getToolbar());
        }
    }

Y el siguiente es el código adicional que construye el cajón dada una barra de herramientas ...

private Drawer BuildDrawerWithToolbar(DrawerBuilder drawerBuilder, ViewGroup activityLayout, Toolbar optionalToolbar) {

        AttachToolbarToLayout(activityLayout, optionalToolbar);

        // Create the drawer
        return drawerBuilder
                .withToolbar(optionalToolbar)
                .withActionBarDrawerToggle(true)
                .withActionBarDrawerToggleAnimated(true)
                .build();
    }

Maldita sea.
Espero que esto quede lo suficientemente claro.
Lo siento, mi código es un poco complejo. Tengo una gran tarea que cumplir, pero mis conocimientos en Android son un WIP, jaja. Espero que el código esté bien :)

Avísame si puedes pescar algo, Mike.
Realmente agradezco la ayuda y las respuestas rápidas.

Se actualizó el formato para facilitar el acceso

@mikepenz ¿Cómo usaría fragmentos para hacer esto? No estoy tan familiarizado con los fragmentos.

@acosti perdón por la respuesta tardía. Es bastante complejo lo anterior. Quizás sea más fácil publicar un "zip" que contenga el código de muestra simple

@ caralin3 si tiene una actividad con fragmentos. Simplemente use el oyente y cambie los fragmentos si el usuario selecciona uno nuevo

@mikepenz ¿Tiene un enlace que me pueda ayudar a crear un fragmento?

@ caralin3 la documentación oficial de Android muestra cómo enviar fragmentos a una vista de contenedor
https://developer.android.com/guide/components/fragments.html

simplemente use el oyente para detectar selecciones del usuario y cambie el fragmento

hola @mikepenz ,

Estoy probando un nuevo enfoque: en lugar de volver a dibujar el cajón de nuevo en cada actividad, y en lugar de tener la implementación "1 actividad - muchos fragmentos":

Haré 1 actividad, muchas actividades.
es decir, hay una actividad de cajón, responsable de sostener el cajón y dibujarlo UNA VEZ.
y al navegar - el setContentView tiene una anulación que obtiene el diseño de destino, lo infla y lo coloca en el diseño de la actividad de un cajón en un "marco de contenido".

Entonces, básicamente, supongo que la misma implementación que tendría con los fragmentos, excepto con las actividades y la autogestión.

Mi pregunta es, ¿cómo abordaría esa solución?

Estaba entreteniendo la idea de simplemente (espero que sea simple) anular el diseño del cajón para agregar el "marco de contenido". a partir de ahí, debería ser fácil hacer la inflación del diseño en la anulación de setContentView. ¿tus pensamientos?

¿Soneone lo intentó con Dagger2?

@acosti Recuerdo que había una biblioteca que hacía exactamente esto. Manteniendo una actividad pero llenándola de diferentes puntos de vista según el contexto.

No estoy muy seguro de si este es un enfoque bueno o el mejor. Android viene con un concepto bastante bueno y rico en funciones de Fragment s que hará exactamente lo que necesita.

También es bastante simple dividir las cosas en fragmentos y manejar fragmentos y hacer el cambio con Drawer ya que solo necesita confirmar el fragmento correcto cuando se selecciona un elemento. Incluso puede mover toda la lógica de confirmación del fragmento al Listener del cajón, ya que puede activarlo después del inicio, y también cuando se llama a onCreate con onSavedInstanceState configurando el fragmento correcto nuevamente.

Ok para finalmente cerrar este problema. Después de investigar, depurar e intentar un poco más. Realmente no es posible reutilizar el mismo DrawerBuilder , ya que resulta que el RecyclerView no está contento si se reutiliza el Adapter .

La solución óptima para este caso de uso es recordar los datos complejos que tiene que buscar y luego simplemente construir el cajón con los elementos, basándose en los datos ya cargados.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

jehad-suliman picture jehad-suliman  ·  3Comentarios

sonh picture sonh  ·  3Comentarios

Erwinstein picture Erwinstein  ·  3Comentarios

oleynikd picture oleynikd  ·  4Comentarios

ghost picture ghost  ·  3Comentarios