web-dev-qa-db-fra.com

Android: la hauteur de SlidingDrawer peut-elle être définie avec wrap_content?

J'essaie d'implémenter une SlidingDrawer qui occupera toute la largeur de l'écran, mais dont la hauteur est déterminée dynamiquement par son contenu: autrement dit, le comportement de disposition standard de fill_parent pour la largeur et de wrap_content pour la hauteur. C'est exactement ce que j'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, elle ne représente qu'environ la moitié de la hauteur de l'écran, ce qui me laisse un grand vide en dessous. Ce que je voudrais, c’est que le contenu soit parfaitement placé au bas de l’écran.

J'ai tout essayé pour y remédier, mais rien n'a fonctionné jusqu'à présent. Si je règle le layout_height de SlidingDrawer 's sur une valeur spécifique (par exemple, 160dip), cela fonctionne, mais ce n'est pas ce dont j'ai besoin: il doit être dynamique. Bien entendu, je me suis assuré que la hauteur de tous les éléments enfants était définie sur wrap_content.

La documentation sur SlidingDrawer est un peu vague à ce sujet et je n'ai pas été en mesure de trouver d'exemples qui fassent ce que je recherche 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>
56
Mark Whitaker

La méthode onMeasure() de la classe SlidingDrawer substitue fondamentalement les modes de présentation à fill_parent, raison pour laquelle layout_height="wrap_content" ne fonctionne pas.

Pour résoudre 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 présentation XML en remplaçant <SlidingDrawer ...> par <fully.qualified.package.ClassName ...>.

Notez que, puisque le tiroir ne remplira plus la disposition parente, vous devrez la placer dans un LinearLayout avec l'attribut gravity défini sur le bord où devrait se trouver le tiroir.

Vous trouverez ci-dessous 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 de présentation (en supposant que WrappingSlidingDrawer se trouve dans le package 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>
126
seydhe

juste mis à pmargin dans un tiroir coulissant dans votre xml

Android:layout_marginTop="50dip"
5
A B

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

Le premier argument de getAttributeIntValue doit être l'espace de noms complet, pas seulement "Android". Donc, l'extrait de code devrait ê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 à le faire fonctionner avec un tiroir coulissant horizontal jusqu'à ce que je réalise qu'il ne trouvait pas l'attribut orientation et le traitait donc comme vertical.

5
museofwater

il est préférable de lire le paramètre sans coder en dur 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 question 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();
    }
4
kingston

malheureusement, vous ne pouvez pas régler la hauteur, mais plutôt le contraire. L'attribut topOffset déterminera la taille du tiroir coulissant, mais sa taille à raser plutôt que sa taille.

2
schwiz

Ça marche 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>
...
0
Alex K