Android: can I set the height of a SlidingDrawer using wrap_content?

I am trying to implement a SlidingDrawer that will occupy the entire width of the screen, but whose height is determined dynamically by its contents: in other words, the standard layout behavior fill_parent for width and wrap_content for height. This is exactly how I indicated it in the XML layout (see below), but the sliding drawer always opens to the full height of the screen. The height of my content varies, but usually it’s about half the height of the screen, so I get a big space under it. I would like the content to sit neatly at the bottom of the screen.

I tried everything I could think of to fix this, but so far nothing has worked. If I set SlidingDrawer layout_height to a specific value (e.g. 160dip ), it works, but that’s not what I need: it should be dynamic. Of course, I made sure that all children are also set to wrap_content .

The SlidingDrawer documentation is a bit vague about this, and I could not find a single example that would do what I needed. If someone can understand where I'm going, I would really appreciate your help!

 <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> 
+55
android layout slidingdrawer
Sep 06 '10 at 21:53 on
source share
6 answers

The onMeasure() method of the onMeasure() class basically overrides layout modes to fill_parent , so layout_height="wrap_content" does not work.

To get around this, you can extend SlidingDrawer with the onMeasure() method, which satisfies the layout_width and layout_height . You can then use this custom class in your XML layout by replacing <SlidingDrawer ...> with <fully.qualified.package.ClassName ...> .

Please note: since the box will no longer fill the parent layout, you will have to enclose it in LinearLayout with the gravity attribute set to the edge where the box should be.

Below is the class I created for this purpose, and an example layout.

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

Layout example (assuming WrappingSlidingDrawer is in 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> 
+125
Nov 24 '10 at 10:05
source share

just install on pmargin in a sliding box in xml

 android:layout_marginTop="50dip" 
+5
09 Feb '12 at 18:47
source share

Seydhe's answer has a slight problem.

The first argument to getAttributeIntValue should be the full namespace, not just "android". Therefore, the code snippet should be:

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

I had problems getting this to work with a horizontal sliding drawer until I realized that he did not find the orientation attribute and therefore considered it to be vertical.

+5
Mar 20 '12 at 18:40
source share

it is better to read the parameter without hard-coding the string:

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

Another issus is in onMeasure.

I used the following code:

  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
Jun 20 '12 at 13:00
source share

Unfortunately, you cannot set the height, but rather the opposite. the topOffset attribute will determine how tall it is to make a sliding box, but it needs to be shaved off, not as height.

+2
Sep 06 '10 at 21:59
source share

This works for me:

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

XML layout:

 ... <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
Feb 05 '16 at 4:15
source share



All Articles