2010-09-06 19 views
55

Estoy tratando de implementar un SlidingDrawer que ocupará el ancho de la pantalla completa, pero cuya altura está determinada dinámicamente por su contenido: en otras palabras, el comportamiento de diseño estándar fill_parent para el ancho y wrap_content para la altura. 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.Android: ¿se puede configurar la altura de SlidingDrawer con wrap_content?

He intentado todo lo que puedo pensar para solucionarlo pero nada ha funcionado hasta ahora. Si configuro el SlidingDrawer como layout_height en 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> 

Respuesta

125

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 solucionar esto, puede ampliar SlidingDrawer con un método onMeasure() reimplementado que cumple 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.

clase WrappingSlidingDrawer:

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

Ejemplo de composición (suponiendo WrappingSlidingDrawer está en com.package paquete):

<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> 
+0

¡Cosas geniales! Luché durante semanas con este problema del cajón deslizante. ¡Muchas gracias! – Gratzi

+0

Es bueno n me ayudó mucho ... gracias :) – Hussain

+0

Fantástico: gracias por una respuesta tan detallada y lo siento, me tomó tanto tiempo para llegar a aceptarlo! –

2

lamentablemente no se puede 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á.

+0

En realidad, yo hice la gestión para establecer la altura (que a mí he mencionado anteriormente) dando una altura explícita a SlidingDrawer: parece que la solución topOffset es otra forma de lograr lo mismo. (También encontré ejemplos donde esto se hace, pero hasta ahora ninguno usando wrap_content.) –

+0

El widget de panel de este tipo te permite establecer la altura con wrap_content entre otras cosas agradables http://www.anddev.org/viewtopic.php? p = 16622 – schwiz

5

apenas se fija a pmargin en el cajón deslizante en su xml

android:layout_marginTop="50dip" 
5

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 que 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); 

que estaba teniendo problemas para conseguir que esto funcione con un cajón deslizante horizontal hasta que me di cuenta que no era encontrar el atributo de orientación y, por tanto, la estaba tratando como vertical.

+1

+1 - Esto me ayudó hoy. ¡Gracias! – Tom

+0

Esto no debería haber sido una respuesta. Sugerir una edición en su lugar. –

4

es mejor para leer el parámetro sin codificar 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); 

Otra issus está en el onMeasure.

He utilizado 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(); 
    } 
+2

+1 - Usé la primera mejora para evitar la codificación rígida. Un pequeño cambio que tuve que hacer fue cómo obtener el valor de TopOffset: topOffset = (int) a.getDimension (1, 0); – Tom

+0

Actualizó el código. Gracias – kingston

0

Funciona para mí:

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> 
... 
Cuestiones relacionadas