2010-09-06 43 views
55

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

我试过了所有我能想到的解决方法,但目前为止没有任何工作。如果我将SlidingDrawerlayout_height设置为一个特定值(例如160dip),它可以工作,但这不是我所需要的:它必须是动态的。当然,我已确保所有子元素的高度都设置为wrap_content

SlidingDrawer上的文档有点含糊其词,我还没有找到任何能够做我后来做的事情的例子。如果任何人都能看到我要出错的地方,我会非常感谢你的帮助!

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

回答

125

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

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

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

下面是我为此创建的类和示例布局。

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

好东西!这个滑动抽屉问题让我挣扎了好几个星期。非常感谢! – Gratzi 2010-11-25 08:08:46

+0

它的好n帮助了我很多..谢谢:) – Hussain 2011-04-13 09:40:08

+0

奇妙:感谢这样一个详细的答案,并对不起,它花了我很长的时间来接受它! – 2011-08-04 09:54:48

2

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

+0

其实我还是设法设置高度(为我”上面提到)通过给SlidingDrawer提供一个明确的高度:看起来像topOffset解决方案是实现相同目标的另一种方式。 (我也发现了这样做的例子,但到目前为止没有使用wrap_content。) – 2010-09-06 22:11:54

+0

这个家伙的面板小部件可以让你用wrap_content设置高度以及其他好东西http://www.anddev.org/viewtopic.php? p = 16622 – schwiz 2010-09-07 01:39:20

5

只设置在在XML滑动抽屉以pmargin

android:layout_marginTop="50dip" 
5

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

我遇到了麻烦这与水平滑动抽屉工作,直到我意识到,这是没有找到方向的属性,因此是把它当作垂直。

+1

+1 - 今天帮助我。谢谢! – Tom 2012-11-08 16:24:00

+0

这不应该是一个答案。建议编辑。 – 2015-11-10 14:32:44

4

这是更好地读取参数没有硬编码字符串:

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

另一个伊苏斯是在onMeasure。

我用下面的代码:

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 - 我使用第一个改进来避免硬编码。我必须做的一个小改变是如何获得topOffset值:topOffset =(int)a.getDimension(1,0); – Tom 2012-11-08 18:54:19

+0

更新了代码。谢谢 – kingston 2012-11-09 10:38:45

0

它为我的作品:

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> 
... 
相关问题