Подтвердить что ты не робот

Android: можно установить высоту SlidingDrawer с помощью wrap_content?

Я пытаюсь реализовать SlidingDrawer, который будет занимать всю ширину экрана, но высота которого определяется динамически по его содержимому: другими словами, стандартное поведение макета fill_parent для ширины и wrap_content для высота. Именно так я указал его в XML-макете (см. Ниже), но скользящий ящик всегда открывается на всю высоту экрана. Высота моего контента варьируется, но обычно это примерно половина высоты экрана, поэтому я получаю большой пробел под ним. Я бы хотел, чтобы контент сидел аккуратно в нижней части экрана.

Я пробовал все, что мог придумать, чтобы исправить это, но пока ничего не работало. Если я установил SlidingDrawer layout_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>
4b9b3361

Ответ 1

Метод onMeasure() класса SlidingDrawer в основном переопределяет режимы макета до fill_parent, поэтому layout_height="wrap_content" не работает.

Чтобы обойти это, вы можете расширить SlidingDrawer с помощью повторно реализованного метода onMeasure(), который удовлетворяет атрибутам layout_width и layout_height. Затем вы можете использовать этот настраиваемый класс в своем XML-макете, заменив <SlidingDrawer ...> на <fully.qualified.package.ClassName ...>.

Обратите внимание: поскольку ящик больше не будет заполнять родительский макет, вам придется заключить его в 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>

Ответ 2

просто установите на pmargin в скользящем ящике в xml

android:layout_marginTop="50dip"

Ответ 3

Ответ 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);

У меня возникли проблемы с тем, чтобы это работало с горизонтальным скользящим ящиком, пока я не понял, что он не нашел атрибут ориентации и поэтому рассматривал его как вертикальный.

Ответ 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);

Другой issus находится в 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();
    }

Ответ 5

К сожалению, вы не можете установить высоту, а скорее наоборот. атрибут topOffset определит, насколько высок, чтобы сделать скользящий ящик, но его нужно сбрить, а не как высоту.

Ответ 6

Это работает для меня:

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