Я обнаружил, что если высота содержимого равна 0, то анимация не будет воспроизводиться, поэтому пришлось установить значение 1 перед анимацией.

ли простой способ создавать расширяемые / складывающиеся блоки, как это видно в официальном приложении на рынке?

Снимок экрана приложения Market, когда вы нажимаете кнопку «Дополнительно», раздел описания расширяется анимацией:

я знаюSlidingDrawer но он не подходит для подобных вещей - он должен быть помещен в оверлей и не поддерживает полуоткрытые состояния.

Обновить:

Вот мое полуработающее решение. Это пользовательский виджет, который расширяетLinearLayout, Это вроде работает, но плохо обрабатывает крайние случаи, например, высота содержимого меньшеcollapsedHeight параметр. Я уверен, что при достаточном внимании, копании в коде и экспериментировании причуды могут быть исправлены. Надеюсь избежать этого и сэкономить время, используя готовое официальное или стороннее решение. Во всяком случае, вот оно, код:

package com.example.androidapp.widgets;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

import com.example.androidapp.R;

public class ExpandablePanel extends LinearLayout {

    private final int mHandleId;
    private final int mContentId;

    private View mHandle;
    private View mContent;

    private boolean mExpanded = true;
    private int mCollapsedHeight = 0;
    private int mContentHeight = 0;

    public ExpandablePanel(Context context) {
        this(context, null);
    }

    public ExpandablePanel(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.ExpandablePanel, 0, 0);

        // How high the content should be in "collapsed" state
        mCollapsedHeight = (int) a.getDimension(
            R.styleable.ExpandablePanel_collapsedHeight, 0.0f);

        int handleId = a.getResourceId(R.styleable.ExpandablePanel_handle, 0);
        if (handleId == 0) {
            throw new IllegalArgumentException(
                "The handle attribute is required and must refer "
                    + "to a valid child.");
        }

        int contentId = a.getResourceId(R.styleable.ExpandablePanel_content, 0);
        if (contentId == 0) {
            throw new IllegalArgumentException(
                "The content attribute is required and must refer "
                    + "to a valid child.");
        }

        mHandleId = handleId;
        mContentId = contentId;

        a.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mHandle = findViewById(mHandleId);
        if (mHandle == null) {
            throw new IllegalArgumentException(
                "The handle attribute is must refer to an"
                    + " existing child.");
        }

        mContent = findViewById(mContentId);
        if (mContent == null) {
            throw new IllegalArgumentException(
                "The content attribute is must refer to an"
                    + " existing child.");
        }

        mHandle.setOnClickListener(new PanelToggler());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mContentHeight == 0) {
            // First, measure how high content wants to be
            mContent.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
            mContentHeight = mContent.getMeasuredHeight();
        }

        // Then let the usual thing happen
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private class PanelToggler implements OnClickListener {
        public void onClick(View v) {
            Animation a;
            if (mExpanded) {
                a = new ExpandAnimation(mContentHeight, mCollapsedHeight);
            } else {
                a = new ExpandAnimation(mCollapsedHeight, mContentHeight);
            }
            a.setDuration(500);
            mContent.startAnimation(a);
            mExpanded = !mExpanded;
        }
    }

    private class ExpandAnimation extends Animation {
        private final int mStartHeight;
        private final int mDeltaHeight;

        public ExpandAnimation(int startHeight, int endHeight) {
            mStartHeight = startHeight;
            mDeltaHeight = endHeight - startHeight;
        }

        @Override
        protected void applyTransformation(float interpolatedTime,
            Transformation t) {
            android.view.ViewGroup.LayoutParams lp = mContent.getLayoutParams();
            lp.height = (int) (mStartHeight + mDeltaHeight * interpolatedTime);
            mContent.setLayoutParams(lp);
        }

        @Override
        public boolean willChangeBounds() {
            // TODO Auto-generated method stub
            return true;
        }
    }
}

Вотres/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="ExpandablePanel">
    <attr name="handle" format="reference" />
    <attr name="content" format="reference" />
    <attr name="collapsedHeight" format="dimension" />
  </declare-styleable>
</resources>

И вот как я использую это в макете:

<com.example.androidapp.widgets.ExpandablePanel
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    example:handle="@+id/expand"
    example:content="@+id/value"
    example:collapsedHeight="50dip">
    <TextView
        android:id="@id/value"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:maxHeight="50dip"
        />
    <Button
        android:id="@id/expand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="More" />
</com.example.androidapp.widgets.ExpandablePanel>

Ответы на вопрос(4)

Ваш ответ на вопрос