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>
Ответы
Ответ 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="<"
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>
...