2010-09-06 34 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> 
... 
相關問題