android layout slidingdrawer

Android: ¿se puede configurar la altura de SlidingDrawer con wrap_content?



layout (6)

Estoy intentando implementar un SlidingDrawer que ocupe todo el ancho de la pantalla, pero cuya altura se determina dinámicamente por su contenido: en otras palabras, el comportamiento estándar de layout fill_parent para el ancho y el wrap_content para el alto. Así es exactamente como lo he especificado en el formato XML (ver a continuación), pero el cajón deslizante siempre se abre a la altura de la pantalla completa. La altura de mi contenido varía, pero generalmente es solo la mitad de la altura de la pantalla, así que termino con un gran espacio debajo. Lo que me gustaría es que el contenido se siente prolijamente en la parte inferior de la pantalla.

Intenté todo lo que pude pensar para solucionarlo, pero nada ha funcionado hasta ahora. Si configuro el SlidingDrawer de layout_height a un valor específico (por ejemplo, 160dip ) funciona, pero eso no es lo que necesito: tiene que ser dinámico. Por supuesto, me he asegurado de que todos los elementos secundarios tengan su altura establecida en wrap_content también.

La documentación sobre SlidingDrawer es un poco vaga en esto y no he podido encontrar ningún ejemplo que haga lo que busco tampoco. Si alguien puede ver dónde me está yendo mal, ¡realmente apreciaría su ayuda!

<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <ViewFlipper android:id="@+id/ImageFlipper" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/imageView0" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="centerCrop" /> <ImageView android:id="@+id/imageView1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="centerCrop" /> <ImageView android:id="@+id/imageView2" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="centerCrop" /> </ViewFlipper> <SlidingDrawer android:id="@+id/infoDrawer" android:layout_width="fill_parent" android:layout_height="wrap_content" android:handle="@+id/infoDrawerHandle" android:content="@+id/infoDrawerContent" android:allowSingleTap="false" android:layout_alignParentBottom="true" android:orientation="vertical" > <!-- Sliding drawer handle --> <ImageView android:id="@id/infoDrawerHandle" android:src="@drawable/info_handle_closed" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- Sliding drawer content: a scroller containing a group of text views laid out in a LinearLayout --> <ScrollView android:id="@id/infoDrawerContent" android:background="@drawable/info_background" android:layout_width="wrap_content" android:layout_height="wrap_content" android:fillViewport="false" > <LinearLayout android:id="@id/infoDrawerContent" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="5dip" > <TextView android:id="@+id/infoTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="16dip" android:textStyle="bold" /> <TextView android:id="@+id/infoCreator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="14dip" android:textStyle="italic" android:paddingBottom="10dip" /> <TextView android:id="@+id/infoDescription" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="14dip" android:paddingBottom="10dip" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffcc00" android:textSize="14dip" android:textStyle="bold" android:text="@string/heading_pro_tip" /> <TextView android:id="@+id/infoProTip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffcc00" android:textSize="14dip" /> </LinearLayout> </ScrollView> </SlidingDrawer> </RelativeLayout>


El método onMeasure() de la clase SlidingDrawer básicamente anula los modos de diseño a fill_parent , por eso layout_height="wrap_content" no funciona.

Para evitar esto, puede extender SlidingDrawer con un método onMeasure() que respete los atributos layout_width y layout_height . A continuación, puede utilizar esta clase personalizada en su diseño XML reemplazando <SlidingDrawer ...> con <fully.qualified.package.ClassName ...> .

Tenga en cuenta que dado que el cajón ya no estará rellenando el diseño principal, deberá encerrarlo en un LinearLayout con el atributo de gravedad establecido en el borde donde debería estar el cajón.

A continuación hay una clase que he creado para este propósito y un diseño de ejemplo.

EnvolviendoSlidingDrawer class:

import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.SlidingDrawer; public class WrappingSlidingDrawer extends SlidingDrawer { public WrappingSlidingDrawer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); int orientation = attrs.getAttributeIntValue("android", "orientation", ORIENTATION_VERTICAL); mTopOffset = attrs.getAttributeIntValue("android", "topOffset", 0); mVertical = (orientation == SlidingDrawer.ORIENTATION_VERTICAL); } public WrappingSlidingDrawer(Context context, AttributeSet attrs) { super(context, attrs); int orientation = attrs.getAttributeIntValue("android", "orientation", ORIENTATION_VERTICAL); mTopOffset = attrs.getAttributeIntValue("android", "topOffset", 0); mVertical = (orientation == SlidingDrawer.ORIENTATION_VERTICAL); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { throw new RuntimeException("SlidingDrawer cannot have UNSPECIFIED dimensions"); } final View handle = getHandle(); final View content = getContent(); measureChild(handle, widthMeasureSpec, heightMeasureSpec); if (mVertical) { int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset; content.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, heightSpecMode)); heightSpecSize = handle.getMeasuredHeight() + mTopOffset + content.getMeasuredHeight(); widthSpecSize = content.getMeasuredWidth(); if (handle.getMeasuredWidth() > widthSpecSize) widthSpecSize = handle.getMeasuredWidth(); } else { int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset; getContent().measure(MeasureSpec.makeMeasureSpec(width, widthSpecMode), heightMeasureSpec); widthSpecSize = handle.getMeasuredWidth() + mTopOffset + content.getMeasuredWidth(); heightSpecSize = content.getMeasuredHeight(); if (handle.getMeasuredHeight() > heightSpecSize) heightSpecSize = handle.getMeasuredHeight(); } setMeasuredDimension(widthSpecSize, heightSpecSize); } private boolean mVertical; private int mTopOffset; }

Diseño de ejemplo (suponiendo que WrappingSlidingDrawer está en paquete com.package):

<FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> ... stuff you want to cover at full-size ... <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="bottom" android:orientation="vertical"> <com.package.WrappingSlidingDrawer android:layout_width="fill_parent" android:layout_height="wrap_content" android:content="@+id/content" android:handle="@+id/handle"> ... handle and content views ... </com.package.WrappingSlidingDrawer> </LinearLayout> </FrameLayout>


Esto funciona para mi:

private SlidingDrawer rightSlidingPanel = null; @Override public void onCreate( Bundle savedInstanceState ) { ... rightSlidingPanel = (SlidingDrawer) findViewById( R.id.rightSlidingPanel ); rightSlidingPanel.post( new Runnable() { @Override public void run() { rightSlidingPanel.getLayoutParams().width = findViewById( R.id.sliding_content2 ).getMeasuredWidth() + findViewById( R.id.sliding_handle ).getMeasuredWidth(); } }); }

Diseño XML:

... <SlidingDrawer android:id="@+id/rightSlidingPanel" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:allowSingleTap="true" android:animateOnClick="true" android:content="@+id/sliding_content" android:handle="@+id/sliding_handle" android:orientation="horizontal" > <Button android:id="@+id/sliding_handle" style="@style/toolbar_button" android:layout_width="30dp" android:layout_height="wrap_content" android:height="40dp" android:text="&lt;" android:width="25dp" /> <LinearLayout android:id="@+id/sliding_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="top" android:orientation="vertical" > <LinearLayout android:id="@+id/sliding_content2" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center_horizontal" > ... </LinearLayout> </LinearLayout> </SlidingDrawer> ...


La respuesta de Seydhe tiene un pequeño problema.

El primer argumento de getAttributeIntValue debe ser el espacio de nombre completo, no solo "android". Por lo tanto, el fragmento de código debe ser:

final String xmlns="http://schemas.android.com/apk/res/android"; int orientation = attrs.getAttributeIntValue(xmlns, "orientation", SlidingDrawer.ORIENTATION_VERTICAL); mTopOffset = attrs.getAttributeIntValue(xmlns, "topOffset", 0);

Estaba teniendo problemas para hacer que funcione con un cajón deslizante horizontal hasta que me di cuenta de que no estaba encontrando el atributo de orientación y, por lo tanto, lo estaba tratando como vertical.


desafortunadamente no puedes establecer la altura, sino todo lo contrario. el atributo topOffset determinará qué tan alto debe hacer el cajón deslizante, pero es qué afeitarse en lugar de qué tan alto será.


es mejor leer el parámetro sin hardcoding de la cadena:

int attrOrientation = android.R.attr.orientation; int attrTopOffset = android.R.attr.topOffset; int[] attrIds = new int [] {attrOrientation, attrTopOffset}; TypedArray a = context.obtainStyledAttributes(attrs, attrIds); int orientation = a.getInt(0, SlidingDrawer.ORIENTATION_VERTICAL); topOffset = a.getDimension(1, 0); a.recycle(); isVertical = (orientation == SlidingDrawer.ORIENTATION_VERTICAL);

Otro issus está en onMeasure.

Use el siguiente código:

if (isVertical) { int height = heightSpecSize - handle.getMeasuredHeight() - topOffset; getContent().measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); heightSpecSize = handle.getMeasuredHeight() + topOffset + content.getMeasuredHeight(); widthSpecSize = content.getMeasuredWidth(); if (handle.getMeasuredWidth() > widthSpecSize) widthSpecSize = handle.getMeasuredWidth(); } else { int width = widthSpecSize - handle.getMeasuredWidth() - topOffset; getContent().measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.UNSPECIFIED)); widthSpecSize = handle.getMeasuredWidth() + topOffset + content.getMeasuredWidth(); heightSpecSize = content.getMeasuredHeight(); if (handle.getMeasuredHeight() > heightSpecSize) heightSpecSize = handle.getMeasuredHeight(); }


simplemente configúralo en pmargin en un cajón deslizante en tu xml

android:layout_marginTop="50dip"