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>
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>
juste mis à pmargin dans un tiroir coulissant dans votre xml
Android:layout_marginTop="50dip"
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.
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();
}
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.
Ç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="<"
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>
...