Android:SlidingDrawer的高度可以用wrap_content来设置吗?

我试图实现一个SlidingDrawer将占据整个屏幕宽度,但其高度是由其内容dynamic确定的:换句话说,宽度的标准fill_parent布局行为和高度的wrap_content 。 这正是我在布局XML中指定的方式(见下文),但滑动抽屉总是打开到全屏高度。 我的内容高度各不相同,但通常只有屏幕高度的一半左右,所以我最终在它下面留下了很大的空隙。 我想要的内容是整齐地坐在屏幕的底部。

我已经尝试了所有我能想到的方法来解决这个问题,但目前为止还没有成功。 如果我将SlidingDrawerlayout_height为一个特定的值(例如160dip ),它就可以工作,但这不是我所需要的:它必须是dynamic的。 当然,我已经确定所有的子元素的高度都设置为wrap_content

关于SlidingDrawer的文档有点含糊不清,而且我还没有find任何可以做我之后做的事情的例子。 如果有人能看到我要去哪里,我真的很感激你的帮助!

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

SlidingDrawer类的onMeasure()方法基本上覆盖了布局模式fill_parent ,这就是为什么layout_height="wrap_content"不起作用。

为了解决这个问题,可以使用一个重新实现的onMeasure()方法来扩展SlidingDrawer,该方法将尊重layout_widthlayout_height属性。 然后,您可以在XML布局中使用此自定义类,方法是将<SlidingDrawer ...>replace为<fully.qualified.package.ClassName ...>

请注意,由于抽屉将不再填充父布局,因此您必须将其放在LinearLayout中,并将重力属性设置为抽屉的边缘。

下面是我为此创build的一个类和一个示例布局。

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

示例布局(假设WrappingSlidingDrawer位于包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> 

只需在xml中的滑动抽屉中设置为pmargin即可

 android:layout_marginTop="50dip" 

seydhe的答案有一个小问题。

getAttributeIntValue的第一个参数需要是完整的命名空间,而不仅仅是“android”。 所以代码片段应该是:

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

我很难得到这个水平滑动抽屉工作,直到我意识到,它没有find方向属性,因此把它视为垂直。

读取参数不需要硬编码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); 

另一个问题是在测量。

我使用了下面的代码:

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

不幸的是,你不能设置高度,而是相反。 topOffset属性将确定滑动抽屉的高度,但确定要刮掉的高度,而不是高度。

它适用于我:

 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布局:

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