2010-09-06 4 views
55

J'essaye d'implémenter un SlidingDrawer qui occupera toute la largeur de l'écran, mais dont la hauteur est déterminée dynamiquement par son contenu: en d'autres termes, le comportement de mise en page fill_parent standard pour la largeur et wrap_content pour la hauteur. C'est exactement comme cela que je l'ai spécifié dans la mise en page XML (voir ci-dessous) mais le tiroir coulissant s'ouvre toujours à la hauteur de l'écran. La hauteur de mon contenu varie, mais en général, il ne mesure que la moitié de la hauteur de l'écran, donc je me retrouve avec un grand écart en dessous. Ce que je voudrais, c'est que le contenu soit soigneusement placé en bas de l'écran. J'ai essayé tout ce que je peux penser pour résoudre ce problème, mais rien n'a fonctionné jusqu'à présent. Si je mets layout_height à une valeur spécifique (par exemple 160dip), cela fonctionne, mais ce n'est pas ce dont j'ai besoin: il doit être dynamique. Bien sûr, je me suis assuré que tous les éléments enfants ont leur hauteur définie à wrap_content aussi.Android: la hauteur de SlidingDrawer peut-elle être définie avec wrap_content?

La documentation sur SlidingDrawer est un peu vague sur ce point et je n'ai pas été capable de trouver des exemples qui font ce que je veux non plus. Si quelqu'un peut voir où je me trompe, j'apprécierais vraiment votre aide!

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

Répondre

125

La méthode onMeasure() de la classe SlidingDrawer substitue fondamentalement les modes de disposition à fill_parent, c'est pourquoi layout_height="wrap_content" ne fonctionne pas.

Pour contourner ce problème, vous pouvez étendre SlidingDrawer avec une méthode onMeasure() réimplémentée qui respecte les attributs layout_width et layout_height. Vous pouvez ensuite utiliser cette classe personnalisée dans votre mise en page XML en remplaçant <SlidingDrawer ...> par <fully.qualified.package.ClassName ...>.

Notez que puisque le tiroir ne remplira plus la mise en page parent, vous devrez l'inclure dans un LinearLayout avec l'attribut de gravité défini sur le bord où le tiroir doit être.

Voici une classe que j'ai créée à cet effet et un exemple de mise en page.

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

Exemple mise en page (en supposant WrappingSlidingDrawer est en com.package paquet):

<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

Des trucs géniaux! J'ai lutté pendant des semaines avec ce problème de tiroirs coulissants. Merci beaucoup! – Gratzi

+0

Son bon n m'a beaucoup aidé .. merci :) – Hussain

+0

Fantastique: merci pour une réponse si détaillée et désolé, il m'a fallu si longtemps pour obtenir l'acceptation! –

2

Malheureusement, vous ne pouvez pas définir la hauteur, mais plutôt le contraire de cela. L'attribut topOffset déterminera la hauteur du tiroir coulissant, mais c'est ce qu'il faut raser plutôt que sa hauteur.

+0

En fait, j'ai réussi à régler la hauteur (comme je l » mentionné ci-dessus) en donnant une hauteur explicite au SlidingDrawer: on dirait que la solution topOffset est une autre façon de réaliser la même chose. (J'ai également trouvé des exemples où cela est fait, mais jusqu'à présent, aucun utilisant wrap_content.) –

+0

Le widget du panneau de ce type vous permet de définir la hauteur avec wrap_content parmi d'autres choses sympas http://www.anddev.org/viewtopic.php? p = 16622 – schwiz

5

juste mis à pmargin dans le tiroir coulissant dans votre xml

android:layout_marginTop="50dip" 
5

la réponse de seydhe a un petit problème.

Le premier argument de getAttributeIntValue doit être l'espace de nom complet, pas seulement "android". Donc, l'extrait de code doit être:

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

j'avais du mal à obtenir que cela fonctionne avec un tiroir coulissant horizontal jusqu'à ce que je me suis aperçu qu'il ne trouvait pas l'attribut d'orientation et a donc le traiter comme vertical.

+1

+1 - Cela m'a aidé aujourd'hui. Je vous remercie! – Tom

+0

Cela n'aurait pas dû être une réponse. Suggérer une modification à la place. –

4

il est préférable de lire le paramètre sans hardcoding la chaîne:

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

Une autre Issos est dans le onMeasure.

J'ai utilisé le code suivant:

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 - J'ai utilisé la première amélioration pour éviter le codage en dur. Une modification mineure que j'ai dû faire était comment obtenir la valeur topOffset: topOffset = (int) a.getDimension (1, 0); – Tom

+0

Mise à jour du code. Merci – kingston

0

Il fonctionne pour moi:

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

      }); 
} 

Mise en page 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> 
...