安卓:可以SlidingDrawer的高度来设置WRAP_CONTENT?高度、SlidingDrawer、WRAP_CONTENT

2023-09-11 12:53:01 作者:Weanhear.(软弱的心脏)

我想实现一个 SlidingDrawer 将占据整个屏幕的宽度,但其高度是通过动态的内容决定的:换句话说,标准 FILL_PARENT 布局行为$为高度和宽度 WRAP_CONTENT 。这正是我如何定义它的布局XML(见下文),但滑动抽屉总是打开全屏幕的高度。我的内容的高度各不相同,但通常它是只有大约一半的屏幕高度,所以我结束了在它下面有很大差距。我想是内容坐在整齐地在屏幕的底部。

我已经试过所有我能想到的解决这个问题,但没有到目前为止在努力。如果我设置了 SlidingDrawer layout_height 为特定值(如 160dip )它的工作原理,但是这不是我所需要的:它必须是动态的。当然,我确信所有的子元素有自己的高度设置为 WRAP_CONTENT 了。

在SlidingDrawer的文档是一个比较含糊的这一点,我一直没能找到做什么,我以后无论是任何的例子。如果任何人都可以看到我要去哪里错了,我真的很AP preciate您的帮助!

 < RelativeLayout的
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =FILL_PARENT>

    < ViewFlipper
        机器人:ID =@ + ID / ImageFlipper
        机器人:layout_width =FILL_PARENT
        机器人:layout_height =FILL_PARENT>

        < ImageView的
            机器人:ID =@ + ID / imageView0
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =FILL_PARENT
            机器人:scaleType =centerCrop/>

        < ImageView的
            机器人:ID =@ + ID / imageView1
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =FILL_PARENT
            机器人:scaleType =centerCrop/>

        < ImageView的
            机器人:ID =@ + ID / imageView2
            机器人:layout_width =FILL_PARENT
            机器人:layout_height =FILL_PARENT
            机器人:scaleType =centerCrop/>

    < / ViewFlipper>

    < SlidingDrawer
        机器人:ID =@ + ID / infoDrawer
        机器人:layout_width =FILL_PARENT
        机器人:layout_height =WRAP_CONTENT
        机器人:手柄=@ + ID / infoDrawerHandle
        机器人:CONTENT =@ + ID / infoDrawerContent
        机器人:allowSingleTap =假
        机器人:layout_alignParentBottom =真
        机器人:方向=垂直>

        <! - 滑动抽屉手柄 -​​ >
        < ImageView的
            机器人:ID =@ ID / infoDrawerHandle
            机器人:SRC =@可绘制/ info_handle_closed
            机器人:layout_width =WRAP_CONTENT
            机器人:layout_height =WRAP_CONTENT/>

        <  - 滑动抽屉内容:含有一组文字意见卷轴
        奠定了在LinearLayout中 - >
        <滚动型
            机器人:ID =@ ID / infoDrawerContent
            机器人:背景=@可绘制/ info_background
            机器人:layout_width =WRAP_CONTENT
            机器人:layout_height =WRAP_CONTENT
            机器人:fillViewport =假>

            <的LinearLayout
                机器人:ID =@ ID / infoDrawerContent
                机器人:方向=垂直
                机器人:layout_width =WRAP_CONTENT
                机器人:layout_height =WRAP_CONTENT
                机器人:paddingRight =5dip>

                <的TextView
                    机器人:ID =@ + ID / infoTitle
                    机器人:layout_width =WRAP_CONTENT
                    机器人:layout_height =WRAP_CONTENT
                    机器人:文字颜色=#FFFFFF
                    机器人:TEXTSIZE =16dip
                    机器人:TEXTSTYLE =黑体/>

                <的TextView
                    机器人:ID =@ + ID / infoCreator
                    机器人:layout_width =WRAP_CONTENT
                    机器人:layout_height =WRAP_CONTENT
                    机器人:文字颜色=#FFFFFF
                    机器人:TEXTSIZE =14dip
                    机器人:TEXTSTYLE =斜体
                    机器人:paddingBottom会=10dip/>

                <的TextView
                    机器人:ID =@ + ID / infoDescription
                    机器人:layout_width =WRAP_CONTENT
                    机器人:layout_height =WRAP_CONTENT
                    机器人:文字颜色=#FFFFFF
                    机器人:TEXTSIZE =14dip
                    机器人:paddingBottom会=10dip/>

                <的TextView
                    机器人:layout_width =WRAP_CONTENT
                    机器人:layout_height =WRAP_CONTENT
                    机器人:文字颜色=#FFCC00
                    机器人:TEXTSIZE =14dip
                    机器人:TEXTSTYLE =黑体
                    机器人:文本=@字符串/ heading_pro_tip/>

                <的TextView
                    机器人:ID =@ + ID / infoProTip
                    机器人:layout_width =WRAP_CONTENT
                    机器人:layout_height =WRAP_CONTENT
                    机器人:文字颜色=#FFCC00
                    机器人:TEXTSIZE =14dip/>

            < / LinearLayout中>

        < /滚动型>

    < / SlidingDrawer>

< / RelativeLayout的>
 

解决方案

在SlidingDrawer类的 onMeasure()方法基本上覆盖布局模式,以 FILL_PARENT ,这也就是为什么 layout_height =WRAP_CONTENT是行不通的。

我的第一个Android项目

要解决这个问题,你可以扩展SlidingDrawer了重新实现 onMeasure()方法荣誉的 layout_width layout_height 属性。 SlidingDrawer ...>然后,您可以通过替换&LT使用自定义类在你的XML布局< fully.qualified.package.ClassName ...>

请注意,由于抽屉将不再灌父布局,则必须将其括在与重力的LinearLayout属性设置为那里边的抽屉应该的。

下面是我已经为此创建一个类的实例布局。

WrappingSlidingDrawer类:

 进口android.content.Context;
进口android.util.AttributeSet;
进口android.view.View;
进口android.widget.SlidingDrawer;


公共类WrappingSlidingDrawer扩展SlidingDrawer {

    公共WrappingSlidingDrawer(上下文的背景下,ATTRS的AttributeSet,诠释defStyle){
        超(背景下,ATTRS,defStyle);

        INT方向= attrs.getAttributeIntValue(机器人,方向,ORIENTATION_VERTICAL);
        mTopOffset = attrs.getAttributeIntValue(机器人,topOffset,0);
        mVertical =(定向== SlidingDrawer.ORIENTATION_VERTICAL);
    }

    公共WrappingSlidingDrawer(上下文的背景下,ATTRS的AttributeSet){
        超(背景下,ATTRS);

        INT方向= attrs.getAttributeIntValue(机器人,方向,ORIENTATION_VERTICAL);
        mTopOffset = attrs.getAttributeIntValue(机器人,topOffset,0);
        mVertical =(定向== SlidingDrawer.ORIENTATION_VERTICAL);
    }

    @覆盖
    保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){

        INT widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        INT widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);

        INT heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        INT heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        如果(widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED){
            抛出新的RuntimeException(SlidingDrawer不能有不定的尺寸);
        }

        最后查看手柄= getHandle();
        最后查看的内容=的getContent();
        measureChild(手柄,widthMeasureSpec,heightMeasureSpec);

        如果(mVertical){
            INT高= heightSpecSize  -  handle.getMeasuredHeight() -  mTopOffset;
            content.measure(widthMeasureSpec,MeasureSpec.makeMeasureSpec(高度,heightSpecMode));
            heightSpecSize = handle.getMeasuredHeight()+ mTopOffset + content.getMeasuredHeight();
            widthSpecSize = content.getMeasuredWidth();
            如果(handle.getMeasuredWidth()> widthSpecSize)widthSpecSize = handle.getMeasuredWidth();
        }
        其他 {
            INT宽度= widthSpecSize  -  handle.getMeasuredWidth() -  mTopOffset;
            。getContent()以测量(MeasureSpec.makeMeasureSpec(宽,widthSpecMode),heightMeasureSpec);
            widthSpecSize = handle.getMeasuredWidth()+ mTopOffset + content.getMeasuredWidth();
            heightSpecSize = content.getMeasuredHeight();
            如果(handle.getMeasuredHeight()> heightSpecSize)heightSpecSize = handle.getMeasuredHeight();
        }

        setMeasuredDimension(widthSpecSize,heightSpecSize);
    }

    私人布尔mVertical;
    私人诠释mTopOffset;
}
 

例布局(假设WrappingSlidingDrawer是包com.package):

 <的FrameLayout机器人:layout_width =FILL_PARENT
             机器人:layout_height =FILL_PARENT>
    ......东西你想覆盖全尺寸的...
    < LinearLayout中的android:layout_width =FILL_PARENT
              机器人:layout_height =FILL_PARENT
              机器人:重力=底
              机器人:方向=垂直>
        < com.package.WrappingSlidingDrawer机器人:layout_width =FILL_PARENT
                           机器人:layout_height =WRAP_CONTENT
                           机器人:CONTENT =@ + ID /内容
                           机器人:手柄=@ + ID /手柄>
            ...手柄和内容的意见...
        < /com.package.WrappingSlidingDrawer>
    < / LinearLayout中>
< /的FrameLayout>
 

I'm trying to implement a SlidingDrawer that will occupy the full screen width, but whose height is determined dynamically by its contents: in other words, standard fill_parent layout behaviour for the width and wrap_content for the height. That's exactly how I've specified it in the layout XML (see below) but the sliding drawer always opens to the full screen height. The height of my content varies, but typically it's only about half the screen height, so I end up with a big gap underneath it. What I'd like is for the content to sit neatly on the bottom of the screen.

I've tried everything I can think of to fix it but nothing's worked so far. If I set the SlidingDrawer's layout_height to a specific value (e.g. 160dip) it works, but that's not what I need: it has to be dynamic. Of course I've made sure all the child elements have their height set to wrap_content too.

The documentation on SlidingDrawer is a bit vague on this and I haven't been able to find any examples that do what I'm after either. If anyone can see where I'm going wrong I'd 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>

解决方案

The onMeasure() method of the SlidingDrawer class basically overrides the layout modes to fill_parent, this is why layout_height="wrap_content" is not working.

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

Note that since the drawer will no longer be filling the parent layout, you will have to enclose it in a LinearLayout with the gravity attribute set to the edge where the drawer should be.

Below are a class I have 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;
}

Example layout (assuming WrappingSlidingDrawer is in 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>